This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Cmd+Shift+Enter.

library(tidyverse)
library(ggplot2)
library(plotly)
library(naniar)
library(scales)
library(dplyr)
library(glmnet)
library(caret)
library(viridis)
library(reshape2)
options(scipen = 999)
#Import data from csv and change datatypes of the columns excluding the columns which are not necessary
raw_data<-read_csv('data/capstone_remit_claims_data.csv')
Parsed with column specification:
cols(
  .default = col_character(),
  date_of_service = col_datetime(format = ""),
  acct_mm = col_double(),
  acct_yyyy = col_double(),
  claim_number = col_double(),
  remit_number = col_double(),
  patient_id = col_double(),
  modality_cost_code = col_double(),
  cost_code = col_double(),
  contract_number = col_double(),
  type_of_care = col_double(),
  remit_total_charged = col_double(),
  remit_total_paid = col_double(),
  remit_allowed_amount = col_double(),
  remits_units = col_double()
)
See spec(...) for full column specifications.
423 parsing failures.
 row                  col               expected actual                                  file
1432 cost_code            no trailing characters   -    'data/capstone_remit_claims_data.csv'
1433 cost_code            no trailing characters   -    'data/capstone_remit_claims_data.csv'
1966 remit_allowed_amount a double                 NULL 'data/capstone_remit_claims_data.csv'
1967 remit_allowed_amount a double                 NULL 'data/capstone_remit_claims_data.csv'
1968 remit_allowed_amount a double                 NULL 'data/capstone_remit_claims_data.csv'
.... .................... ...................... ...... .....................................
See problems(...) for more details.
 
#chnage the columns datatypes to correct data types
df<-raw_data %>%
  mutate(patient_id = as.factor(patient_id),
         location_id = as.factor(location_id),
         #cost_code = as.factor(cost_code),
         modality_cost_code = as.character(modality_cost_code),
         remit_allowed_amount = as.double(remit_allowed_amount),
         contract_number = as.factor(contract_number),
         hct_per = as.double(hct_per),
         epo_units = as.integer(epo_units),
         pcn_payer_code = as.factor(pcn_payer_code),
         type_of_care = as.factor(type_of_care),
         date_of_service = as.Date(date_of_service)
         ) %>% 
  select(-epo_units,-modifier_4,-modifier_5)
NAs introduced by coercionNAs introduced by coercion
 
df<-df %>% 
  mutate('modality' = case_when(modality_cost_code %in% c('1220','1230',"1121") ~ "PD",
                                modality_cost_code %in% c('1110',"1210","1310","1510") ~ "HEMO",
                                modality_cost_code %in% c('1330',"1320") ~ "HOME",
                                TRUE ~ "OTHERS"))

 

df<-df %>% replace_with_na (replace = list(diagnosis_code = 'NULL', urr_modifier = 'NULL',modifier_1 = 'NULL',modifier_2='NULL',modifier_3='NULL'))
df <- df %>% 
      mutate( 'percentage_payment' =  remit_total_paid/remit_total_charged * 100) 
 
#SAVE DATAFRAME
saveRDS(df,'clean_df_for_EDA.RDS')

#payors
payors<-as.data.frame(unique(df$pcn_payer_code))
colnames(payors)<-c("payors")

saveRDS(payors,'DCI_capstone/data/payors.rds')

PREPARE A DATAFRAME WHICH CAN BE USED FOR ALGORITHMS

#delete unnecessary columns
algo_df<-df %>% 
 select (-date_of_service,-acct_mm,-acct_yyyy,-claim_number,-remit_number,-location_id,-patient_id,-contract_number,-urr_modifier,-description,-percentage_payment)   
 
#dummize categorical columns
dummy_cols <- c("modality_cost_code","diagnosis_code","type_of_care","revenue_code", "modifier_1","modifier_2","modifier_3","revenue_code","hcpc_code","pcn_payer_code")

algo_df<-fastDummies::dummy_columns(algo_df,select_columns = c(dummy_cols),ignore_na = TRUE)
 
#replace na's to 0's
algo_df[is.na(algo_df)]<- 0

 
algo_df_final<-algo_df %>% 
   mutate( 'percentage_payment' =  remit_total_paid/remit_total_charged * 100) %>% 
  select (-modality_cost_code,-cost_code,-diagnosis_code,-type_of_care,-revenue_code,-hcpc_code,-modifier_1,-modifier_2,-modifier_3,-pcn_payer_code,-remit_total_charged,-remit_total_paid,-remits_units,-remit_allowed_amount,-modality)

#SAVE DATAFRAME
saveRDS(algo_df_final,'clean_df_for_algorithm.RDS')
str(algo_df_final)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   11754 obs. of  125 variables:
 $ hct_per                : num  33.3 0 33.3 0 33.3 33.3 0 33.3 0 33.3 ...
 $ modality_cost_code_1220: int  1 1 0 0 0 0 0 0 0 0 ...
 $ modality_cost_code_1330: int  0 0 1 1 1 1 1 1 1 1 ...
 $ modality_cost_code_1110: int  0 0 0 0 0 0 0 0 0 0 ...
 $ modality_cost_code_1320: int  0 0 0 0 0 0 0 0 0 0 ...
 $ modality_cost_code_1310: int  0 0 0 0 0 0 0 0 0 0 ...
 $ modality_cost_code_1510: int  0 0 0 0 0 0 0 0 0 0 ...
 $ modality_cost_code_1210: int  0 0 0 0 0 0 0 0 0 0 ...
 $ modality_cost_code_1230: int  0 0 0 0 0 0 0 0 0 0 ...
 $ modality_cost_code_1121: int  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_Z23     : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_I50.9   : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_J06.9   : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_L03.129 : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_T88.8XXA: num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_E87.70  : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_R68.83  : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_I50.32  : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_N25.81  : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_D50.9   : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_G63     : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_J91.8   : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_E11.621 : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_E87.5   : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_L03.116 : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_D63.1   : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_M61.48  : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_L03.91  : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_Z11.1   : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_E83.39  : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_N39.0   : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_L97.514 : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_I50.20  : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_B96.89  : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_M86.079 : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_R11.2   : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_Z86.31  : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_Z89.519 : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_I38     : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_I96     : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_B95.62  : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_G47.33  : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_I10     : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_I48.91  : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_N18.6   : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_T82.7XXA: num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_R50.9   : num  0 0 0 0 0 0 0 0 0 0 ...
 $ diagnosis_code_I33.0   : num  0 0 0 0 0 0 0 0 0 0 ...
 $ type_of_care_71        : int  0 0 0 0 0 0 0 0 0 0 ...
 $ type_of_care_73        : int  1 1 0 0 0 0 0 0 0 0 ...
 $ type_of_care_74        : int  0 0 1 1 1 1 1 1 1 1 ...
 $ type_of_care_76        : int  0 0 0 0 0 0 0 0 0 0 ...
 $ type_of_care_84        : int  0 0 0 0 0 0 0 0 0 0 ...
 $ type_of_care_87        : int  0 0 0 0 0 0 0 0 0 0 ...
 $ revenue_code_0841      : int  1 1 0 0 0 0 0 0 0 0 ...
 $ revenue_code_0851      : int  0 0 1 1 1 1 1 1 1 1 ...
 $ revenue_code_0821      : int  0 0 0 0 0 0 0 0 0 0 ...
 $ revenue_code_0636      : int  0 0 0 0 0 0 0 0 0 0 ...
 $ revenue_code_0771      : int  0 0 0 0 0 0 0 0 0 0 ...
 $ revenue_code_0270      : int  0 0 0 0 0 0 0 0 0 0 ...
 $ revenue_code_0831      : int  0 0 0 0 0 0 0 0 0 0 ...
 $ revenue_code_0306      : int  0 0 0 0 0 0 0 0 0 0 ...
 $ revenue_code_0300      : int  0 0 0 0 0 0 0 0 0 0 ...
 $ modifier_1_G5          : num  0 0 0 0 0 0 0 0 0 0 ...
 $ modifier_1_G3          : num  0 0 0 0 0 0 0 0 0 0 ...
 $ modifier_1_G1          : num  0 0 0 0 0 0 0 0 0 0 ...
 $ modifier_1_G4          : num  0 0 0 0 0 0 0 0 0 0 ...
 $ modifier_1_AY          : num  0 0 0 0 0 0 0 0 0 0 ...
 $ modifier_1_G6          : num  0 0 0 0 0 0 0 0 0 0 ...
 $ modifier_1_G2          : num  0 0 0 0 0 0 0 0 0 0 ...
 $ modifier_1_JA          : num  0 0 0 0 0 0 0 0 0 0 ...
 $ modifier_1_V6          : num  0 0 0 0 0 0 0 0 0 0 ...
 $ modifier_2_V6          : num  0 0 0 0 0 0 0 0 0 0 ...
 $ modifier_2_V5          : num  0 0 0 0 0 0 0 0 0 0 ...
 $ modifier_2_V7          : num  0 0 0 0 0 0 0 0 0 0 ...
 $ modifier_2_KX          : num  0 0 0 0 0 0 0 0 0 0 ...
 $ modifier_2_JE          : num  0 0 0 0 0 0 0 0 0 0 ...
 $ modifier_3_V7          : num  0 0 0 0 0 0 0 0 0 0 ...
 $ modifier_3_V6          : num  0 0 0 0 0 0 0 0 0 0 ...
 $ modifier_3_KX          : num  0 0 0 0 0 0 0 0 0 0 ...
 $ hcpc_code_90993        : int  1 1 0 0 0 0 0 0 0 0 ...
 $ hcpc_code_90945        : int  0 0 1 1 1 1 1 1 1 1 ...
 $ hcpc_code_90999        : int  0 0 0 0 0 0 0 0 0 0 ...
 $ hcpc_code_90686        : int  0 0 0 0 0 0 0 0 0 0 ...
 $ hcpc_code_90747        : int  0 0 0 0 0 0 0 0 0 0 ...
 $ hcpc_code_G0010        : int  0 0 0 0 0 0 0 0 0 0 ...
 $ hcpc_code_G0008        : int  0 0 0 0 0 0 0 0 0 0 ...
 $ hcpc_code_A4913        : int  0 0 0 0 0 0 0 0 0 0 ...
 $ hcpc_code_J0696        : int  0 0 0 0 0 0 0 0 0 0 ...
 $ hcpc_code_J3370        : int  0 0 0 0 0 0 0 0 0 0 ...
 $ hcpc_code_G0009        : int  0 0 0 0 0 0 0 0 0 0 ...
 $ hcpc_code_90732        : int  0 0 0 0 0 0 0 0 0 0 ...
 $ hcpc_code_90670        : int  0 0 0 0 0 0 0 0 0 0 ...
 $ hcpc_code_J0713        : int  0 0 0 0 0 0 0 0 0 0 ...
 $ hcpc_code_A4657        : int  0 0 0 0 0 0 0 0 0 0 ...
 $ hcpc_code_J0690        : int  0 0 0 0 0 0 0 0 0 0 ...
 $ hcpc_code_J1644        : int  0 0 0 0 0 0 0 0 0 0 ...
 $ hcpc_code_J1270        : int  0 0 0 0 0 0 0 0 0 0 ...
 $ hcpc_code_J2916        : int  0 0 0 0 0 0 0 0 0 0 ...
  [list output truncated]
df
#Final checks
sum(is.na(algo_df_final))
[1] 0

SUMMARY ANALYSIS

#Charged
summary(df$remit_total_charged)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   19.7   870.0  1910.0  1444.3  2010.0  2643.0 
#Paid
summary(df$remit_total_paid)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   0.05   86.61  168.36  154.49  208.80  729.32 
charges_dis_plt<-df %>% 
                  ggplot(aes(x=remit_total_charged, y = ..density..))  + 
                  geom_histogram(breaks = seq(0,2800,by=100 ),bins = 10, binwidth = 0.05,
                  fill =  "chartreuse4", alpha = 0.6) +
                  labs(x="Charges", y = "Counts",title = "Distribution of Charges")+
                  theme_minimal()+
                  geom_density(color = "red", alpha=0.4)+
                  scale_y_continuous(breaks = seq(0,10000,1000))+
                  scale_x_continuous(breaks = seq(0,3000,500))
ggplotly(charges_dis_plt  )

NA
payment_dis_plt<-df %>% 
              ggplot(aes(x=remit_total_paid,y=..density..))  + 
              geom_histogram(breaks = seq(0,2800,by=100 ),bins = 10, binwidth = 0.05,
                 fill =  "chartreuse4", alpha = 0.6) +
                 labs(x="Payments", y = "Counts",title = "Distribution of Payments")+
                 theme_minimal()+
                 geom_density(color = "red",alpha = 0.4)+
                 scale_y_continuous(breaks = seq(0,10000,1000))+
                scale_x_continuous(breaks = seq(0,3000,500))
ggplotly(payment_dis_plt  )
pl<- ggplot(df,aes(x=remit_total_charged,y=remit_total_paid) )+
  geom_point(alpha= 0.7) 
  ggplotly(pl)
 
dci_data_total<-df %>% 
            filter(acct_yyyy == 2017) %>% 
            select('Charges' = remit_total_charged,'Payments'=remit_total_paid)

dci_long <- reshape2::melt(dci_data_total)
No id variables; using all as measure variables
#saveRDS(dci_long,'dist_plts.rds')

dist_plts<-ggplot(dci_long, aes(value,y = ..density..)) + facet_wrap(~variable, scales = 'free_x') +
           geom_density(color = "red",alpha = 0.4)+
           labs(title = "Distribution")+
           geom_histogram( fill =  "chartreuse4", alpha = 0.6)+
 # geom_vline(aes(xintercept = mean(value,na.rm=T)),color = "red", linetype = "dashed",size = 1) +
           scale_y_continuous(breaks = seq(0,10000,1000))+
           scale_x_continuous(breaks = seq(0,3000,500))

dist_plts

df %>% 
  ggplot(aes(x=remit_total_paid)) + geom_histogram(binwidth = 50)

df %>% 
  ggplot(aes(x=remit_total_paid,fill = modality)) + 
    geom_vline(aes(xintercept = mean(remit_total_paid,na.rm=T)),color = "red", linetype = "dashed",size = 1) +
  geom_histogram(bins=40,binwidth = 10, center = 0.05,alpha = 0.8)

cbp1 <- c("#999999", "#E69F00", "#56B4E9", "#009E73",
          "#F0E442", "#0072B2", "#D55E00", "#CC79A7")
dist_box_modality<-df %>% 
                  filter(acct_yyyy == 2017) %>% 
                  select(modality,remit_total_paid) %>% 
                  ggplot(aes(  modality, remit_total_paid,alpha = 0.5)) +
                  geom_boxplot(aes(fill=modality)) +
                  theme_classic() +
                  scale_fill_manual(values = cbp1) +
                  ggtitle("Distribution of Payments across Modalities") +
                  labs(x="Modality",y = "Payments")  +
                    theme(legend.position = "none")

ggplotly(dist_box_modality)

NA
payors
payors
df %>% 
                      # filter(pcn_payer_code =='24180402') %>% 
                      #filter(modality == 'PD') %>% 
                       group_by(modality,pcn_payer_code) %>% 
                       summarise(sum_payments= sum(remit_total_paid))

 
total_payments_bar_plt<-df %>% 
                      # filter(pcn_payer_code =='24180402') %>% 
                      #filter(modality == 'PD') %>% 
                       group_by(modality) %>% 
                       summarise(sum_payments= sum(remit_total_paid)) %>% 
                       ggplot(aes(x = modality, y = sum_payments, fill = modality)) +
                       geom_bar(stat = "identity", alpha=0.8) +
                       theme_classic() +
                       labs(
                          x = "Modality",
                          y = "Total Payments",
                          title = "Total Payments by Modality"
                          ) +
                      scale_fill_manual(values = cbp1) +
                      theme(legend.position = "none")

    ggplotly(total_payments_bar_plt)

END OF SUMMARY ANALYSIS

BEGIN TIME SERIS ANALYSIS

 avg_pct_paid_over_time<-df %>% 
  filter(acct_yyyy == 2018) %>% 
  mutate('percentage_paid' = remit_total_paid/remit_total_charged*100) %>% 
  mutate('period' =  paste(acct_mm , '/' , acct_yyyy)) %>% 
  select(acct_mm,acct_yyyy,period,percentage_paid,pcn_payer_code) %>% 
  group_by(acct_mm,period,pcn_payer_code) %>% 
  summarise('avg_pct_paid'=mean(percentage_paid))  

time_plot<-ggplot(avg_pct_paid_over_time, aes( reorder(period,acct_mm) , avg_pct_paid, group = pcn_payer_code, color = pcn_payer_code)) + 
  geom_line(size = 1) +
  geom_point(size=2, shape=6, aes(fill=factor(pcn_payer_code))) +
  theme_minimal()+
  labs(color = "Payors", fill = 'Payors')+
  ylab('Percentage of Payments ') +
  xlab('Month/Year') +
  ylim(0, 50)+
  ggtitle('Percentage of Payments by Payor over time')+ 
  theme(axis.text.x = element_text(angle = 90,hjust=1))

ggplotly(time_plot)
 df %>% 
  filter(acct_yyyy == 2018) %>% 
  mutate('percentage_paid' = remit_total_paid/remit_total_charged*100) %>% 
  mutate('period' =  paste(acct_mm , '/' , acct_yyyy)) %>% 
  select(acct_mm,acct_yyyy,period,percentage_paid,pcn_payer_code) %>% 
  group_by(acct_mm,acct_yyyy,period,pcn_payer_code) %>% 
  summarise('avg_pct_paid'=mean(percentage_paid)) %>% 
  arrange(acct_mm,avg_pct_paid) %>% 
  ggplot(aes( reorder(x = period,acct_mm) ,y = avg_pct_paid,group=1,color=pcn_payer_code,fill=pcn_payer_code)) + 
  geom_point() +
    theme(axis.text.x = element_text(angle = 45,hjust=1))

ANALYSIS BY LOCATION (can be a page)

# payment percentage by location
df %>% 
  group_by(location_id) %>% 
  summarise('Num_of_rows'=n(),
            'Total_charges' = sum(remit_total_charged),
            'Total_payments' = sum(remit_total_paid),
            'percentage_payments' = (Total_payments/Total_charges) * 100,
            ) %>% 
  arrange(desc(Total_charges))
NA

ALANYSIS BY PCN (PAYORS)


# payment percentage by PCN
charge_payments<- df %>% 
                  group_by(pcn_payer_code) %>% 
                  summarise('Num_of_rows'=n(),
                   'Total_charges' = sum(remit_total_charged),
                    'Total_payments' = sum(remit_total_paid),
                     'percentage_payments' = (Total_payments/Total_charges) * 100,
                      ) %>% 
                  arrange(percentage_payments)
charge_payments %>% 
  mutate('mean_percentage_payments' = sum(Total_payments)/sum(Total_charges)*100) %>% 
  mutate('dis_from_avg_per_payment' =  percentage_payments-mean_percentage_payments )
payors_with_good_per<-df %>% 
                      group_by(pcn_payer_code) %>% 
                      summarise('Num_of_rows'=n(),
                                'Total_charges' = sum(remit_total_charged),
                                'Total_payments' = sum(remit_total_paid),
                                'percentage_payments' = (Total_payments/Total_charges) * 100,
                                ) %>% 
                      arrange(desc(Total_charges)) %>% 
                      ggplot(aes(reorder(x=pcn_payer_code,percentage_payments),y=percentage_payments,fill = pcn_payer_code)) +
                      geom_col(alpha=0.8) +
                      theme_minimal()+
                      theme(axis.text.x = element_text(angle = 45,hjust=1))+
                      labs(x='Payors',y="Percentage of charges paid",title = "Which payors are paying good percentage?")

ggplotly(payors_with_good_per)

NA

#Which payer is paying good percentage by modality

df %>% group_by(pcn_payer_code,modality) %>% 
                      summarise('Num_of_rows'=n(),
                                'Total_charges' = sum(remit_total_charged),
                                'Total_payments' = sum(remit_total_paid),
                                'percentage_payments' = (Total_payments/Total_charges) * 100,
                                ) %>% 
                      arrange(desc(Total_charges))
 payors_with_good_per<-df %>% group_by(pcn_payer_code,modality) %>% 
  filter(pcn_payer_code=='02371001') %>% 
                      summarise('Num_of_rows'=n(),
                                'Total_charges' = sum(remit_total_charged),
                                'Total_payments' = sum(remit_total_paid),
                                'percentage_payments' = round((Total_payments/Total_charges) * 100,2)
                                ) %>% 
                      arrange(desc(Total_charges)) %>% 
                      ggplot(aes(reorder(x=modality,percentage_payments),y=percentage_payments,fill = modality)) +
                      geom_col(alpha=0.8) +
                      geom_text(aes(label=percentage_payments), vjust=0) + 
                      theme_minimal()+
                      labs(x='Modality',y="Percentage of charges paid",title = "Percentage of Charges paid by Modality?")+
                      theme( theme(legend.position = "none"))
Error in (function (el, elname)  : 
  Element line must be a element_line object.
df  
NA
NA
 payors_with_good_per<-df %>% group_by(pcn_payer_code,modality) %>% 
  filter(pcn_payer_code=='02371001') %>% 
                      summarise('Num_of_rows'=n(),
                                'Total_charges' = sum(remit_total_charged),
                                'Total_payments' = sum(remit_total_paid),
                                'percentage_payments' = round((Total_payments/Total_charges) * 100,2)
                                ) %>% 
                      arrange(desc(Total_charges)) %>% 
                      ggplot(aes(reorder(x=modality,percentage_payments),y=percentage_payments,fill = modality)) +
                      geom_segment(aes (reorder(x=modality,percentage_payments), xend =modality,y=0,yend = percentage_payments) )+
                      geom_point(color = "orange",size = 4)+
                      theme_minimal()+
    geom_text(aes(label=percentage_payments)) +  
                      labs(x='Modality',y="Percentage of Charges Paid(%)",title = "Percentage of Charges Paid by Modality?")+
                      scale_y_continuous(breaks = seq(0,20,1))+
                      theme(legend.position = "none")
  

ggplotly(payors_with_good_per)

BY LOCAITON, WHICH PAYORS ARE CONTRIBUTING MORE (CAN BE A TAB)

df %>% 
  group_by(location_id,pcn_payer_code) %>% 
  summarise('total_charges'=sum(remit_total_charged),'total_paid' = sum(remit_total_paid)) %>% 
  mutate('loss_amt' = total_charges-total_paid) %>% 
  mutate('payment_percentage' = (total_paid/total_charges)*100) %>% 
  mutate('loss_percentage' = (loss_amt/total_charges) * 100) %>% 
  filter(total_paid!=0) %>% 
  arrange(location_id,desc(payment_percentage))
unique(df$pcn_payer_code)
 [1] 02371001 24180402 06791013 11371008 12320609 21560402 00410417 16181025 00410601 00410825 06771001 00410901 00410235
Levels: 00410235 00410417 00410601 00410825 00410901 02371001 06771001 06791013 11371008 12320609 16181025 21560402 24180402
colnames(df)
 [1] "date_of_service"      "acct_mm"              "acct_yyyy"            "claim_number"         "remit_number"        
 [6] "patient_id"           "location_id"          "modality_cost_code"   "cost_code"            "diagnosis_code"      
[11] "contract_number"      "hct_per"              "urr_modifier"         "type_of_care"         "revenue_code"        
[16] "description"          "hcpc_code"            "remit_total_charged"  "remit_total_paid"     "remit_allowed_amount"
[21] "remits_units"         "modifier_1"           "modifier_2"           "modifier_3"           "pcn_payer_code"      
[26] "modality"             "percentage_payment"  
distinct(df,acct_yyyy,pcn_payer_code ) %>% 
  filter(acct_yyyy==2018) 
df%>% 
                group_by(description) %>% 
                filter (pcn_payer_code =='00410235') %>% 
               summarise('total_charges'=sum(remit_total_charged),'total_paid' = sum(remit_total_paid)) %>% 
                mutate('percentage_of_payments' = round(total_paid/total_charges*100,2)) %>% 
                mutate('per_payment_overall' = round((total_paid/sum(total_paid))*100,2)) 
                #filter(total_paid>0)

Services by each payor type

services_plt <- df%>% 
                group_by(description) %>% 
                filter (pcn_payer_code =='02371001') %>% 
               summarise('total_charges'=sum(remit_total_charged),'total_paid' = sum(remit_total_paid)) %>% 
                mutate('percentage_of_payments' = round(total_paid/total_charges*100,2)) %>% 
                mutate('per_payment_overall' = round((total_paid/sum(total_paid))*100,2)) %>% 
                filter(total_paid>0) %>% 
                ggplot(aes(reorder(x= description,total_paid),y = total_paid,fill = description)) +
                geom_col()+
                coord_flip()+
                theme(axis.text.x = element_text(angle = 45,hjust=1)) +
                theme_minimal()+
                xlab("Services") +
                ylab("Payments") +
                ggtitle("Payments by Services")+
                theme(legend.position = "none") 

ggplotly(services_plt)

FOR WHAT TYPE OF TREATMENT / MEDICATION ARE WE GETTING PAID LESS / MORE THAN 10 PERCENT (CAN BE A PAGE)

x<- df %>% 
      group_by('Description'=description) %>% 
      summarise('total_charges'=sum(remit_total_charged),
      'total_paid' = sum(remit_total_paid)) %>% 
      mutate('percentage_paid' = round(total_paid/total_charges * 100,2)) %>% 
      arrange(desc(percentage_paid)  )

saveRDS(x$Description,'data/meds.rds')
df %>% 
  filter(description == 'ARANESP/DARBEPOETIN ALFA-' ) %>%   
  group_by(description) %>% 
  summarise('TotalCharges'=sum(remit_total_charged),'TotalPaid' = sum(remit_total_paid)) %>% 
 pivot_longer(TotalCharges:TotalPaid,names_to = "Type", values_to = "Charges")
 df %>% 
      group_by('Description'=description) %>% 
      summarise('total_charges'=sum(remit_total_charged),'total_paid' = sum(remit_total_paid)) %>% 
      mutate('percentage' = round(total_paid/total_charges * 100,2)) %>% 
      select (Description,percentage) 

Medications for which less than 10 percent paid

##top cost codes
meds<-df %>% 
  filter(description == 'ARANESP/DARBEPOETIN ALFA-' ) %>%   
  group_by(description) %>% 
  summarise('TotalCharges'=sum(remit_total_charged),'TotalPaid' = sum(remit_total_paid)) %>% 
 pivot_longer(TotalCharges:TotalPaid,names_to = "Type", values_to = "Charges")%>%
  ggplot(aes(x=reorder(description,Charges),y=Charges,fill = Type) ) +
  geom_bar(stat="identity",alpha = 0.8,position = 'dodge') +
  theme(axis.text.x = element_text(angle = 45,hjust=1)) +
  theme_minimal()+
  xlab("Medication") +
  ylab("Dollars") +
  ggtitle("Total Charges vs Total Paid") 

ggplotly(meds)
meds%>% 
      arrange(desc(avg_per_paid))

Difference in payments by modality on medications

#only medications paid by cost_code
meds<- df %>% 
      select(modality_cost_code,cost_code,description,remit_total_charged,remit_total_paid,modality) %>% 
      filter(cost_code>3000 ) %>%  
      mutate('percentage_paid' = round(remit_total_paid/remit_total_charged * 100,2)) %>% 
     group_by(modality, description) %>% 
    summarize('avg_per_paid'=mean(percentage_paid))  

meds<- meds%>% 
      filter(avg_per_paid <54)

options(repr.plot.width = 3, repr.plot.height = 3)

 x<- ggplot(meds,aes(reorder(x=description,avg_per_paid), y = avg_per_paid,fill =  modality )) +
  geom_col(stat="identity",position = 'dodge' ) +
  ggtitle("Medication Payments by Modality") + 
  labs(x="Medications", y = 'Average of percentage Payments') +
  theme(axis.text.x = element_text(angle = 45,hjust=1)) 
Ignoring unknown parameters: stat
 
 ggplotly(x)
df %>% 
  select(modality_cost_code,cost_code,description,remit_total_charged,remit_total_paid) %>% 
    filter(cost_code>3000 & cost_code<5000) %>%  
    mutate('percentage_paid' = round(remit_total_paid/remit_total_charged * 100,2)) %>% 
    group_by(modality_cost_code,cost_code,description) %>% 
  summarize('avg_per_paid'=mean(percentage_paid)) %>% 
  arrange(cost_code,modality_cost_code) 

List of HCPC codes for drugs

distinct(df,cost_code,description,modality_cost_codes) 
Trying to compute distinct() for variables not found in the data:
- `modality_cost_codes`
This is an error, but only a warning is raised for compatibility reasons.
The following variables will be used:
- cost_code
- description
NA
NA

ANALYSIS ON TREATMENTS

treatment_summaries %>% 
ggplot(aes(reorder(x=description,total_paid),y=total_paid,fill = description))+
  geom_bar(stat="identity")+
  coord_flip()+
  theme_bw()+
    theme(axis.text.x = element_text(angle = 45,hjust=1))+
  # geom_text(aes(label=total_paid), vjust=0) + 
  xlab("Treatment Types") +
  ylab("Number of Treatments") +
  ggtitle("Payments by Treatments") +
  theme(legend.position = "none")

NA
treatment_summaries %>% 
ggplot(aes(reorder(x=description,percentage_paid),y=percentage_paid,fill = description))+
  geom_bar(stat="identity")+
  geom_text(aes(label=percentage_paid), vjust=0) + 
  #coord_flip()+
    theme(axis.text.x = element_text(angle = 45,hjust=1))+
  xlab("Treatments") +
  ylab("Percentage of Charges paid back") +
  ggtitle("For which Treatments Good Percentage of Charge is Paid Back")+
    theme(legend.position = "none")



ggdotchart(treatment_summaries, x = "description", y = "percentage_paid",
           color = "description",                                # Color by groups
           palette = c("#999999", "#E69F00", "#56B4E9", "#009E73","#F0E442", "#0072B2", "#D55E00", "#CC79A7"),
           # Custom color palette
           sorting = "ascending",                        # Sort value in descending order
           add = "segments",                             # Add segments from y = 0 to dots
           ggtheme = theme_pubr(),
           size = 8
           ) +
   geom_text(aes(label=percentage_paid), vjust=0,size=3) + 
theme(legend.position = "none") + 
  theme(axis.text.x = element_text(angle = 360,hjust=1))+
  coord_flip() +
  labs(title = "Percentage Paid Back by Treatment Types",x="Treatment Types", y = "Percentage %")

PAYMENTS STRUCTURE OF PAYORS

df %>% 
  group_by(pcn_payer_code) %>% 
 summarise('total_charges'=sum(remit_total_charged),'total_paid' = sum(remit_total_paid)) %>% 
  mutate('percentage_of_payments' = round(total_paid/total_charges*100,2)) %>% 
    mutate('per_payment_overall' = round((total_paid/sum(total_paid))*100,2))
df %>% 
  group_by(pcn_payer_code) %>% 
    filter (pcn_payer_code !='02371001') %>% 
 summarise('total_charges'=sum(remit_total_charged),'total_paid' = sum(remit_total_paid)) %>% 
  mutate('percentage_of_payments' = round(total_paid/total_charges*100,2)) %>% 
    mutate('per_payment_overall' = round((total_paid/sum(total_paid))*100,2)) %>% 
arrange(desc(per_payment_overall))  %>% 
  ggplot(aes(reorder(x=pcn_payer_code,per_payment_overall),y=per_payment_overall,fill = reorder(x=pcn_payer_code,per_payment_overall))) +
  geom_col(stat="identity") +
    theme(axis.text.x = element_text(angle = 90,hjust=1)) +
    theme(legend.position = "none")+
    ggtitle("Other Payors payment percentage")+
    labs(x= "Payors",y="Percentage of Payments")
Ignoring unknown parameters: stat

    theme(legend.position = "none")+
      theme_minimal()
List of 65
 $ legend.position           : chr "right"
 $ line                      :List of 6
  ..$ colour       : chr "black"
  ..$ size         : num 0.5
  ..$ linetype     : num 1
  ..$ lineend      : chr "butt"
  ..$ arrow        : logi FALSE
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_line" "element"
 $ rect                      :List of 5
  ..$ fill         : chr "white"
  ..$ colour       : chr "black"
  ..$ size         : num 0.5
  ..$ linetype     : num 1
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_rect" "element"
 $ text                      :List of 11
  ..$ family       : chr ""
  ..$ face         : chr "plain"
  ..$ colour       : chr "black"
  ..$ size         : num 11
  ..$ hjust        : num 0.5
  ..$ vjust        : num 0.5
  ..$ angle        : num 0
  ..$ lineheight   : num 0.9
  ..$ margin       : 'margin' num [1:4] 0pt 0pt 0pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : logi FALSE
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.title.x              :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : num 1
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 2.75pt 0pt 0pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.title.x.top          :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : num 0
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0pt 0pt 2.75pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.title.y              :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : num 1
  ..$ angle        : num 90
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0pt 2.75pt 0pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.title.y.right        :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : num 0
  ..$ angle        : num -90
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0pt 0pt 0pt 2.75pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.text                 :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : chr "grey30"
  ..$ size         : 'rel' num 0.8
  ..$ hjust        : NULL
  ..$ vjust        : NULL
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.text.x               :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : num 1
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 2.2pt 0pt 0pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.text.x.top           :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : num 0
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0pt 0pt 2.2pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.text.y               :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 1
  ..$ vjust        : NULL
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0pt 2.2pt 0pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.text.y.right         :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 0
  ..$ vjust        : NULL
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0pt 0pt 0pt 2.2pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.ticks                : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ axis.ticks.length         : 'unit' num 2.75pt
  ..- attr(*, "valid.unit")= int 8
  ..- attr(*, "unit")= chr "pt"
 $ axis.ticks.length.x       : NULL
 $ axis.ticks.length.x.top   : NULL
 $ axis.ticks.length.x.bottom: NULL
 $ axis.ticks.length.y       : NULL
 $ axis.ticks.length.y.left  : NULL
 $ axis.ticks.length.y.right : NULL
 $ axis.line                 : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ axis.line.x               : NULL
 $ axis.line.y               : NULL
 $ legend.background         : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ legend.margin             : 'margin' num [1:4] 5.5pt 5.5pt 5.5pt 5.5pt
  ..- attr(*, "valid.unit")= int 8
  ..- attr(*, "unit")= chr "pt"
 $ legend.spacing            : 'unit' num 11pt
  ..- attr(*, "valid.unit")= int 8
  ..- attr(*, "unit")= chr "pt"
 $ legend.spacing.x          : NULL
 $ legend.spacing.y          : NULL
 $ legend.key                : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ legend.key.size           : 'unit' num 1.2lines
  ..- attr(*, "valid.unit")= int 3
  ..- attr(*, "unit")= chr "lines"
 $ legend.key.height         : NULL
 $ legend.key.width          : NULL
 $ legend.text               :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : 'rel' num 0.8
  ..$ hjust        : NULL
  ..$ vjust        : NULL
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ legend.text.align         : NULL
 $ legend.title              :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 0
  ..$ vjust        : NULL
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ legend.title.align        : NULL
 $ legend.direction          : NULL
 $ legend.justification      : chr "center"
 $ legend.box                : NULL
 $ legend.box.margin         : 'margin' num [1:4] 0cm 0cm 0cm 0cm
  ..- attr(*, "valid.unit")= int 1
  ..- attr(*, "unit")= chr "cm"
 $ legend.box.background     : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ legend.box.spacing        : 'unit' num 11pt
  ..- attr(*, "valid.unit")= int 8
  ..- attr(*, "unit")= chr "pt"
 $ panel.background          : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ panel.border              : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ panel.spacing             : 'unit' num 5.5pt
  ..- attr(*, "valid.unit")= int 8
  ..- attr(*, "unit")= chr "pt"
 $ panel.spacing.x           : NULL
 $ panel.spacing.y           : NULL
 $ panel.grid                :List of 6
  ..$ colour       : chr "grey92"
  ..$ size         : NULL
  ..$ linetype     : NULL
  ..$ lineend      : NULL
  ..$ arrow        : logi FALSE
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_line" "element"
 $ panel.grid.minor          :List of 6
  ..$ colour       : NULL
  ..$ size         : 'rel' num 0.5
  ..$ linetype     : NULL
  ..$ lineend      : NULL
  ..$ arrow        : logi FALSE
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_line" "element"
 $ panel.ontop               : logi FALSE
 $ plot.background           : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ plot.title                :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : 'rel' num 1.2
  ..$ hjust        : num 0
  ..$ vjust        : num 1
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0pt 0pt 5.5pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ plot.subtitle             :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 0
  ..$ vjust        : num 1
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0pt 0pt 5.5pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ plot.caption              :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : 'rel' num 0.8
  ..$ hjust        : num 1
  ..$ vjust        : num 1
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 5.5pt 0pt 0pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ plot.tag                  :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : 'rel' num 1.2
  ..$ hjust        : num 0.5
  ..$ vjust        : num 0.5
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ plot.tag.position         : chr "topleft"
 $ plot.margin               : 'margin' num [1:4] 5.5pt 5.5pt 5.5pt 5.5pt
  ..- attr(*, "valid.unit")= int 8
  ..- attr(*, "unit")= chr "pt"
 $ strip.background          : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ strip.placement           : chr "inside"
 $ strip.text                :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : chr "grey10"
  ..$ size         : 'rel' num 0.8
  ..$ hjust        : NULL
  ..$ vjust        : NULL
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 4.4pt 4.4pt 4.4pt 4.4pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ strip.text.x              : NULL
 $ strip.text.y              :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : NULL
  ..$ angle        : num -90
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ strip.switch.pad.grid     : 'unit' num 2.75pt
  ..- attr(*, "valid.unit")= int 8
  ..- attr(*, "unit")= chr "pt"
 $ strip.switch.pad.wrap     : 'unit' num 2.75pt
  ..- attr(*, "valid.unit")= int 8
  ..- attr(*, "unit")= chr "pt"
 - attr(*, "class")= chr [1:2] "theme" "gg"
 - attr(*, "complete")= logi TRUE
 - attr(*, "validate")= logi TRUE
  
  
test <- compare_actuals_to_pred %>% 
                                # filter(!!as.symbol(input$algo_payors) == 1 ) %>% 
                                # filter(!!as.symbol(input$algo_modality) == 1)%>% 
                                filter(pcn_payer_code_02371001 == 1 & hcpc_code_90999==1 ) %>% 
                                select(actual,predicted,percentage_difference ) %>%
                                summarise('Actual' = mean(actual),'Predicted' = mean(predicted)) %>% 
                                pivot_longer(Actual:Predicted,names_to = "Predictions", values_to = "percentage_predicted")

get_percentage_value<-test  %>% 
  filter(Predictions == "Predicted") %>% 
  select(percentage_predicted)

#as.vector(get_percentage_value)
get_percentage_value * 100
NA
Payors_bar_plt<-df %>% 
                  group_by(pcn_payer_code) %>% 
                  summarise('total_charges'=sum(remit_total_charged),'total_paid' = sum(remit_total_paid)) %>% 
                  mutate('percentage_of_payments' = round(total_paid/sum(total_paid)*100,2)) %>% 
                  ggplot(aes(reorder(x=pcn_payer_code,percentage_of_payments),y=percentage_of_payments,fill = pcn_payer_code,text=percentage_of_payments))+
                  theme(axis.text.x = element_text(angle = 90,hjust=1)) +
                  geom_bar(  stat = "identity")+
                  theme(legend.position = "none") +
                  labs(x="Payors",y="Percentage of Total  Payments",Title = "Percentage of Total Payments For Each Payor ")

ggplotly(Payors_bar_plt,tooltip = "text")

PERCENTAGE OF PAYMENTS BY PAYOR

bp<-df %>% 
  group_by(pcn_payer_code) %>% 
 summarise('total_charges'=sum(remit_total_charged),'total_paid' = sum(remit_total_paid)) %>% 
  mutate('percentage_of_payments' = round(total_paid/sum(total_paid)*100,2)) %>% 
  ggplot(aes(x="",y=percentage_of_payments,fill = pcn_payer_code))+
  geom_bar(width = 1, stat = "identity")
bp


 pie_chart <- bp + coord_polar("y",start = 0) +
   labs(title = "Majority of Payments coming from Payor: 02371010") +
   theme_void()  

pie_chart

#92.58
 

TAKE OUT THE MAJOR PAYOR AND SEE HOW OTHERS ARE DOING


bp<-df %>% 
  group_by(pcn_payer_code) %>% 
 summarise('total_charges'=sum(remit_total_charged),'total_paid' = sum(remit_total_paid)) %>% 
  mutate('percentage_of_payments' = round(total_paid/sum(total_paid)*100,2)) %>% 
    mutate('per_payment_overall' = round((total_paid/sum(total_paid))*100,2)) %>% 
  filter(pcn_payer_code !='02371001') %>% 
  ggplot(aes(x="",y=percentage_of_payments,fill = pcn_payer_code))+
  geom_bar(width = 1, stat = "identity")
bp


 pie_chart <- bp + coord_polar("y",start = 0) +
   labs(title = "Payments By Other Payors") +
   theme_void() 
 
   geom_text(aes(y = value/3 + c(0, cumsum(value)[-length(value)]), 
            label = percent(value/100)), size=5)
mapping: y = ~value/3 + c(0, cumsum(value)[-length(value)]), label = ~percent(value/100) 
geom_text: parse = FALSE, check_overlap = FALSE, na.rm = FALSE
stat_identity: na.rm = FALSE
position_identity 
pie_chart

ggplot(df) + 
geom_bar(aes(x=pcn_payer_code, y=remit_total_paid, color=pcn_payer_code),stat="identity") + geom_smooth(aes(x=pcn_payer_code, y=remit_total_paid))+
  theme(axis.text.x = element_text(angle = 90,hjust=1)) +
    theme(legend.position = "none")

PAYMENTS BY TREATMENTS

ts<-treatment_summaries %>% 
 ggplot(aes(x=reorder(description,percentage_paid),y=percentage_paid,fill = description))+
  geom_bar(stat = "identity")+
    theme(axis.text.x = element_text(angle = 45,hjust=1)) +
    theme(legend.position = "none")
ts

NA
NA

PAYMENTS BY NON-TREATMENT SERVICES COST CODES like meds supplies etc


df %>% 
  filter(cost_code >'1510') %>% 
  group_by(cost_code ) %>% 
summarise('total_charges'=sum(remit_total_charged),'total_paid' = sum(remit_total_paid)) %>% 
  mutate('percentage_paid' = total_paid/total_charges * 100) %>% 
  filter(percentage_paid>0) %>% 
  mutate('per_payment_overall' = round((total_paid/sum(total_paid))*100,2)) %>% 
  arrange(desc(per_payment_overall)) %>% 
  ggplot(aes(x= factor(cost_code),y=per_payment_overall,fill = factor(cost_code))) +
  geom_col(stat_count = "identity")+
   theme(axis.text.x = element_text(angle = 90,hjust=2)) +
    theme(legend.position = "none")
Ignoring unknown parameters: stat_count

 
  distinct(df,cost_code,description)%>% 
  filter(cost_code %in% c('3605','3621','7060','3613'))
df %>% 
  select(date_of_service,patient_id,cost_code,remit_total_paid,pcn_payer_code) %>% 
  ggplot(aes(x=as.factor(cost_code),y=remit_total_paid)) +geom_point()+
  theme(axis.text.x = element_text(angle = 90,hjust=1)) +
  labs(x="Cost Codes",y="Total payments",title = "Total Payments by Cost Codes")

IS THERE ANY RELATION BETWEEN PAYMENT AND HCT_PER? NO

ANALYSIS USING MODIFIERS

G1 - Most recent URR of less than 60% G2 - Most recent URR of 60% to 64.9% G3 - Most recent URR of 65% to 69.9% G4 - Most recent URR of 70% to 74.9% G5 - Most recent URR of 75% or greater G6 - ESRD patient for whom less than seven dialysis sessions have been provided in a month.

DIAGNOSIS CODE ANALYSIS

dplyr::count(df,diagnosis_code,sort = TRUE)

N25.81 - Secondary hyperparathyroidism of renal origin Z23 is a billable ICD code used to specify a diagnosis of encounter for immunization.

diagnosis<-df %>% group_by(diagnosis_code) %>% summarise(n=n(),total_charged = sum(remit_total_charged), total_paid = sum(remit_total_paid)) %>% arrange(desc(n))

diagnosis
NA

diagnosis %>% 
  filter(!is.na(diagnosis_code)) %>% 
  ggplot(aes(x=diagnosis_code,y=n,fill=diagnosis_code)) +
  geom_col() +
    theme(axis.text.x = element_text(angle = 90,hjust=1)) 

BEGIN MAKING PERCENTAGE OF PAYMENTS PREDICTION USING REGRESSION ALGORITHMS.

  1. ORDINARY LEAST SQUARES MODEL
#First, split the data in algo_df_final dataset with 75 percentile
set.seed(237)
index = createDataPartition(algo_df_final$hct_per,p=0.75,list = FALSE)

#save the 75% of data in trainSet and 25% in test set.
trainSet <- algo_df_final[index,]
testSet <- algo_df_final[-index,]
#OLS
#train the model 
#ols_ds <- train(percentage_payment~.,data = trainSet,method = "lm", metric ="RMSE", 
 #              trControl = trainControl(method = "none"))

ols_ds <- train(percentage_payment~.,data = trainSet,method = "lm")
prediction from a rank-deficient fit may be misleadingprediction from a rank-deficient fit may be misleadingprediction from a rank-deficient fit may be misleadingprediction from a rank-deficient fit may be misleadingprediction from a rank-deficient fit may be misleadingprediction from a rank-deficient fit may be misleadingprediction from a rank-deficient fit may be misleadingprediction from a rank-deficient fit may be misleadingprediction from a rank-deficient fit may be misleadingprediction from a rank-deficient fit may be misleadingprediction from a rank-deficient fit may be misleadingprediction from a rank-deficient fit may be misleadingprediction from a rank-deficient fit may be misleadingprediction from a rank-deficient fit may be misleadingprediction from a rank-deficient fit may be misleadingprediction from a rank-deficient fit may be misleadingprediction from a rank-deficient fit may be misleadingprediction from a rank-deficient fit may be misleadingprediction from a rank-deficient fit may be misleadingprediction from a rank-deficient fit may be misleadingprediction from a rank-deficient fit may be misleadingprediction from a rank-deficient fit may be misleadingprediction from a rank-deficient fit may be misleadingprediction from a rank-deficient fit may be misleadingprediction from a rank-deficient fit may be misleading
#training set performance
train_pred <- predict(ols_ds, newdata = trainSet)
prediction from a rank-deficient fit may be misleading
MAE(pred = train_pred , obs = trainSet$percentage_payment)#1.555435
[1] 1.555435
print(ols_ds)
Linear Regression 

8818 samples
 124 predictor

No pre-processing
Resampling: Bootstrapped (25 reps) 
Summary of sample sizes: 8818, 8818, 8818, 8818, 8818, 8818, ... 
Resampling results:

  RMSE      Rsquared   MAE     
  3.212291  0.9259262  1.639011

Tuning parameter 'intercept' was held constant at a value of TRUE
#test set
test_pred <- predict (ols_ds, newdata = testSet)
prediction from a rank-deficient fit may be misleading
MAE(pred = test_pred, obs = testSet$percentage_payment) 
[1] 1.652259
print(test_pred)
          1           2           3           4           5           6           7           8           9          10 
 11.3154148  11.3154148  10.5213993   9.1944347   9.8954573   9.8954573   9.1944347   9.1944347   9.1944347   9.1944347 
         11          12          13          14          15          16          17          18          19          20 
  9.8954573   9.1944347  26.8666461  66.1131325  12.6951999  12.6951999  12.6951999  12.6951999  12.6951999  12.6951999 
         21          22          23          24          25          26          27          28          29          30 
 10.1478820  10.7230827  10.7230827  10.7230827   8.9607568   9.4168000   9.4168000   9.1300550   9.1300550   9.1300550 
         31          32          33          34          35          36          37          38          39          40 
  9.1300550   9.3446538   9.3446538   9.2078918   9.2078918   9.2078918   9.4725636   9.4725636   9.4725636   9.4725636 
         41          42          43          44          45          46          47          48          49          50 
  9.6816913   9.6816913   9.6816913   9.6816913   9.6816913   1.4056111   0.7332016  10.0671197  10.0671197  10.0671197 
         51          52          53          54          55          56          57          58          59          60 
 10.0671197  10.0671197  10.0671197  10.0671197  10.0671197  10.0671197  10.0671197  10.0671197  10.0671197  10.0671197 
         61          62          63          64          65          66          67          68          69          70 
 12.6308203  12.6308203  12.6308203  12.6308203  12.6308203  12.6308203  10.1550353  10.1550353  10.4999395  10.4999395 
         71          72          73          74          75          76          77          78          79          80 
 10.4999395  10.4999395  10.4999395  10.4999395  10.4999395  10.4999395  10.4999395  10.4999395  10.4999395  10.4999395 
         81          82          83          84          85          86          87          88          89          90 
 10.4999395   9.0370622   1.2590227   1.2590227   9.0370622   9.0370622   9.9107462   9.9107462   9.7103045   9.7103045 
         91          92          93          94          95          96          97          98          99         100 
  9.7103045   9.7103045  10.9204375   9.9976628  10.9204375  10.9204375  10.9204375   9.9976628  10.9204375   9.9976628 
        101         102         103         104         105         106         107         108         109         110 
 10.9204375   9.9976628   9.9976628  10.9204375   9.9976628   9.9976628   9.9976628   9.9976628   9.9976628   9.9976628 
        111         112         113         114         115         116         117         118         119         120 
  9.9976628   9.9976628   9.9976628   9.9976628   9.9976628   9.9976628   9.9976628   9.9976628   9.9976628   9.9976628 
        121         122         123         124         125         126         127         128         129         130 
  9.9976628   9.9976628   9.9976628   9.9976628   9.9976628   9.9976628   9.9976628   9.9976628   9.9976628   9.9976628 
        131         132         133         134         135         136         137         138         139         140 
  9.9976628   9.9976628   9.9976628   9.9976628   9.9976628   9.9976628   9.9976628   9.9976628   9.9976628   9.9976628 
        141         142         143         144         145         146         147         148         149         150 
  9.9177500   9.9177500  10.3835519  10.1119104  10.3835519   9.9547431   9.9547431  10.9204375   9.9547431   9.9547431 
        151         152         153         154         155         156         157         158         159         160 
  9.9547431   9.9547431  10.9204375  10.9204375  10.9204375   9.9547431  10.9204375   9.9547431   9.9547431  10.9204375 
        161         162         163         164         165         166         167         168         169         170 
  9.9547431  10.9204375   9.9547431   9.9547431   9.9547431   9.9547431   9.9547431   9.9547431   9.9547431   9.9547431 
        171         172         173         174         175         176         177         178         179         180 
  9.9547431   9.9547431   9.9547431   9.9547431   9.9547431   9.9547431   9.9547431   9.9547431   9.9547431   9.9547431 
        181         182         183         184         185         186         187         188         189         190 
  9.9547431   9.9547431   9.9547431   9.9547431   9.9547431   9.9547431   9.9547431   9.9547431   9.9547431   9.9547431 
        191         192         193         194         195         196         197         198         199         200 
  9.9547431   9.9547431   9.9547431   9.9547431   9.9547431   9.9547431   9.9547431  10.3338676  10.4713263  10.4713263 
        201         202         203         204         205         206         207         208         209         210 
 10.4713263  10.4713263  10.4713263  10.4713263  10.4713263  10.4713263  10.4713263  10.4713263  10.4713263  10.4713263 
        211         212         213         214         215         216         217         218         219         220 
 10.4713263  10.4713263  10.4713263  10.4713263  10.4713263  10.4713263  10.4713263   9.5297900   9.5297900   8.8367701 
        221         222         223         224         225         226         227         228         229         230 
 10.0742730  10.0742730  10.0742730  10.0742730  10.0742730  10.0742730   9.7603776   9.4766637   9.9327068  10.6273748 
        231         232         233         234         235         236         237         238         239         240 
  9.4766637  10.1713317  10.1713317   9.4766637  10.1713317   9.4766637   9.7209424   9.4766637  10.0119694  10.9204375 
        241         242         243         244         245         246         247         248         249         250 
 10.0119694  10.9204375  10.0119694  10.9204375  10.0119694  10.9204375  10.0119694  10.9204375  10.9204375  10.0119694 
        251         252         253         254         255         256         257         258         259         260 
 10.0119694  10.0119694  10.0119694  10.0119694  10.0119694  10.0119694  10.0119694  10.0119694  10.0119694  10.0119694 
        261         262         263         264         265         266         267         268         269         270 
 10.0119694  10.0119694  10.0119694  10.0119694  10.0119694  10.0119694  10.0119694  10.0119694  10.0119694  10.0119694 
        271         272         273         274         275         276         277         278         279         280 
 10.0119694  10.0119694  10.0119694  10.0119694  10.0119694  10.0119694  10.0119694  10.0119694  10.0119694  10.0119694 
        281         282         283         284         285         286         287         288         289         290 
 10.0119694  10.0119694  10.0119694  10.0119694  10.0119694  10.0119694  10.0119694  10.0119694  10.0119694  10.0119694 
        291         292         293         294         295         296         297         298         299         300 
 10.0119694  10.1815724  10.1815724  10.1815724  10.0835023  10.0835023  10.0835023  10.0835023  10.0835023  10.2815348 
        301         302         303         304         305         306         307         308         309         310 
 10.2815348  10.2815348  10.2815348  10.2815348  10.2815348  10.6358520  10.6358520  10.6358520  10.6358520  10.6358520 
        311         312         313         314         315         316         317         318         319         320 
 10.6358520  10.6358520   9.1872814   9.1872814   9.1872814   9.2221984   9.2221984   9.7246111  10.1679315  10.1679315 
        321         322         323         324         325         326         327         328         329         330 
 10.1679315  10.4069467  11.3154148  10.4069467  11.3154148  10.4069467  11.3154148  10.4069467  10.4069467  11.3154148 
        331         332         333         334         335         336         337         338         339         340 
 11.3154148  11.3154148  10.4069467  10.4069467  10.4069467  11.3154148  11.3154148  10.4069467  11.3154148  10.4069467 
        341         342         343         344         345         346         347         348         349         350 
 10.4069467  10.4069467  10.4069467  10.4069467  10.4069467  10.4069467  10.4069467  10.4069467  10.4069467  10.4069467 
        351         352         353         354         355         356         357         358         359         360 
 10.4069467  10.4069467  10.4069467  10.4069467  10.4069467  10.4069467  10.4069467  10.4069467  10.4069467  10.4069467 
        361         362         363         364         365         366         367         368         369         370 
 10.4069467  10.4069467  10.0814263  10.0814263  10.6644652  10.6644652  10.6644652   4.4602593  10.6644652  10.6644652 
        371         372         373         374         375         376         377         378         379         380 
 10.6644652  14.8870121  14.4309690  12.1163728  12.1163728   9.1658215   9.1658215   9.1658215   9.2221984  10.0742730 
        381         382         383         384         385         386         387         388         389         390 
 10.0742730  10.2726090  10.2726090  10.2726090  10.2726090  10.1822381  20.9218467  10.1822381  10.1822381  10.5285526 
        391         392         393         394         395         396         397         398         399         400 
 10.5285526  10.5285526  10.5285526  10.5285526  10.5285526  10.5285526  10.5285526  10.0313532  10.0313532  10.0313532 
        401         402         403         404         405         406         407         408         409         410 
 10.0313532  10.0385065  10.0385065  10.0385065  10.0385065  10.5142461  10.5142461  10.5142461  10.5142461  10.5142461 
        411         412         413         414         415         416         417         418         419         420 
 10.5142461  10.5142461  10.5142461  10.5142461  10.5142461  10.5142461  10.5142461  10.5142461  10.5142461  10.5142461 
        421         422         423         424         425         426         427         428         429         430 
 10.5142461  10.5142461  10.5142461  10.4641730  10.4641730  10.4641730  10.4641730  10.4641730  10.4641730  11.6102566 
        431         432         433         434         435         436         437         438         439         440 
 11.6102566  11.6102566  11.6102566   9.1864320   9.1864320   9.1864320  10.0885796  10.0885796   9.7460710   9.7460710 
        441         442         443         444         445         446         447         448         449         450 
  9.7460710   9.7317644   9.7317644   9.7317644   9.7317644  10.0320190  10.0320190  10.0320190  10.0320190   9.9812802 
        451         452         453         454         455         456         457         458         459         460 
  9.9812802   9.9812802  20.9218467  10.8468285   9.9812802   9.9812802  10.8468285   9.9812802  10.8468285  10.8468285 
        461         462         463         464         465         466         467         468         469         470 
  9.9812802   9.9812802  10.4641730  10.4641730  10.4641730  10.4641730  10.0313532  60.1683331  10.0313532  10.0313532 
        471         472         473         474         475         476         477         478         479         480 
 10.0313532  10.0313532  10.0313532  10.0313532  10.0313532  10.0313532  10.0313532  11.1846813  10.6000856  10.6000856 
        481         482         483         484         485         486         487         488         489         490 
 10.6000856  10.6000856  10.6000856  10.6000856  10.6000856  10.6000856  10.6000856  10.6000856  10.6000856  10.6000856 
        491         492         493         494         495         496         497         498         499         500 
 10.6000856  10.6000856  10.6000856  10.6000856  10.6000856  10.6000856  10.6000856  10.6000856  10.6000856  10.6000856 
        501         502         503         504         505         506         507         508         509         510 
 10.6000856  10.6000856   9.2373544   9.2373544   9.2373544   9.2150451   9.2150451   9.2150451   9.7818374  10.0385065 
        511         512         513         514         515         516         517         518         519         520 
 10.0385065  10.0385065  10.0385065   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451 
        521         522         523         524         525         526         527         528         529         530 
  0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451  18.6466643   0.5344451   0.5344451 
        531         532         533         534         535         536         537         538         539         540 
  0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451 
        541         542         543         544         545         546         547         548         549         550 
  0.5344451   0.5344451   0.5344451   0.5344451   0.2577418   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451 
        551         552         553         554         555         556         557         558         559         560 
  0.5344451   0.5344451   0.5344451   0.5344451   0.2577418   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451 
        561         562         563         564         565         566         567         568         569         570 
  0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.2577418   0.5344451 
        571         572         573         574         575         576         577         578         579         580 
  0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451 
        581         582         583         584         585         586         587         588         589         590 
  0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451 
        591         592         593         594         595         596         597         598         599         600 
  0.5344451   0.2577418   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451 
        601         602         603         604         605         606         607         608         609         610 
  0.5344451  18.6466643   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451   0.5344451  18.6466643 
        611         612         613         614         615         616         617         618         619         620 
  0.2577418  10.0027401  10.0027401  10.0027401  10.5213993  10.5213993  10.5213993  10.5213993  10.5213993  10.5213993 
        621         622         623         624         625         626         627         628         629         630 
 10.4371347  10.4371347   9.8531867   9.8531867   9.8531867   9.8531867   9.8531867   9.8531867   9.6816913   9.6816913 
        631         632         633         634         635         636         637         638         639         640 
  9.6816913  60.1683331  10.2244921  10.2244921  10.2244921   9.9177500   9.9177500   9.9177500   9.9177500   9.9177500 
        641         642         643         644         645         646         647         648         649         650 
  9.9177500   9.8247572  20.9218467  60.1683331   9.8247572   9.8247572   9.8247572   9.1721254   9.1721254   9.7889907 
        651         652         653         654         655         656         657         658         659         660 
  9.7889907   9.7889907   9.9240538   9.9240538   9.9240538   9.7031512   9.7031512   9.7031512   9.7031512   9.7532243 
        661         662         663         664         665         666         667         668         669         670 
  9.7532243   9.7532243   9.7532243   9.7532243  10.5442504  10.5442504   7.9468085  98.5740142   9.2150451   9.2150451 
        671         672         673         674         675         676         677         678         679         680 
  9.8954573   9.8954573   9.8954573   9.8954573   9.8954573   9.8954573   9.1157485   9.1157485   9.1157485   9.1157485 
        681         682         683         684         685         686         687         688         689         690 
  9.1157485   9.1157485   9.7389177   9.7389177  10.2408748  10.2408748  10.2408748  10.2408748  10.4713263  10.4713263 
        691         692         693         694         695         696         697         698         699         700 
 10.4713263  10.4713263  10.4713263  10.4713263  10.4713263   9.8986686   9.8986686   9.8986686   9.8986686  10.4355598 
        701         702         703         704         705         706         707         708         709         710 
 10.4355598  10.4355598  10.4355598  11.3154148  10.4355598  10.4355598  11.3154148  11.3154148  11.3154148  10.4355598 
        711         712         713         714         715         716         717         718         719         720 
 11.3154148  11.3154148  10.4355598  10.4355598  10.4355598  10.4355598  10.4355598  80.4289910  80.4289910  80.4289910 
        721         722         723         724         725         726         727         728         729         730 
 80.4289910  80.4289910  80.4289910  80.4289910  10.2654557  10.2654557  10.2654557  10.0885796  10.0885796  10.0885796 
        731         732         733         734         735         736         737         738         739         740 
 10.5142461  10.5142461  10.5142461  10.5142461  10.5142461  10.5142461  10.5142461  10.5142461  10.5142461  10.5142461 
        741         742         743         744         745         746         747         748         749         750 
  9.6673848   9.6673848   9.6673848   9.6673848   9.1864320   9.1864320   9.7603776   9.7603776   9.7603776   9.9741269 
        751         752         753         754         755         756         757         758         759         760 
  9.9741269   9.8319105   9.8319105   9.8319105   9.8319105   9.8319105   9.8319105  13.8052790  13.8052790  13.8052790 
        761         762         763         764         765         766         767         768         769         770 
 13.3602287  13.3602287  13.3602287  13.3602287  13.3602287  13.3602287  12.8096526  12.8096526  66.1131325  14.5264512 
        771         772         773         774         775         776         777         778         779         780 
 10.2623346  10.2623346  11.1059950  13.4677555  13.4677555  12.7452730  13.4677555  12.7452730  12.7452730  12.7452730 
        781         782         783         784         785         786         787         788         789         790 
 10.7302360   9.3824384  10.7302360   1.1177784  60.6697236   9.3824384   9.3824384  10.7302360   9.3824384  10.7302360 
        791         792         793         794         795         796         797         798         799         800 
 10.7302360  10.8468285  10.8468285  10.5500125  10.5500125  10.5500125  60.1683331  10.6944696  10.6944696  10.6944696 
        801         802         803         804         805         806         807         808         809         810 
 10.0241999   9.6959979   9.6959979   9.6959979  98.5740142  98.5740142  98.5740142  10.3459144  10.0742730   9.2651182 
        811         812         813         814         815         816         817         818         819         820 
  9.2651182   9.2651182  10.1407287  10.1407287  10.1407287  10.1407287  10.1407287  10.1407287  10.1407287  10.1407287 
        821         822         823         824         825         826         827         828         829         830 
  9.7532243   9.7532243   9.7532243   9.7532243  10.4141000  20.2034995  10.4141000  10.4141000  10.4141000  10.4141000 
        831         832         833         834         835         836         837         838         839         840 
 10.4141000  10.0170466  10.0170466  10.0170466  10.0170466  10.0170466   9.8319105   9.8319105   9.8319105   9.8319105 
        841         842         843         844         845         846         847         848         849         850 
 13.7623592  13.7623592  13.7623592  13.7623592  14.0040250  14.0040250  14.0040250  14.0040250  14.0040250  14.0040250 
        851         852         853         854         855         856         857         858         859         860 
 11.3311126  11.3311126  11.3311126  11.3311126  10.5142461  10.5142461  10.5142461  10.9416923  10.9416923  10.9416923 
        861         862         863         864         865         866         867         868         869         870 
 10.9416923  10.9416923  10.9416923  10.9416923  10.9416923   9.1515149   9.1515149   9.1515149   9.1515149  10.4999395 
        871         872         873         874         875         876         877         878         879         880 
 10.4999395  10.4999395  10.4999395  10.4999395  10.4999395  10.4999395  10.4999395  10.1393184  10.1393184  10.1393184 
        881         882         883         884         885         886         887         888         889         890 
 10.1393184  10.0313532  10.0313532  10.0313532  10.0313532   9.7317644  11.2070827  20.9218467  11.2070827  10.3369886 
        891         892         893         894         895         896         897         898         899         900 
  9.2293517   9.2293517   9.2293517   9.2293517   9.5815453   9.5815453   9.5815453  10.2583024  10.2583024  10.2583024 
        901         902         903         904         905         906         907         908         909         910 
 10.2583024   9.7460710   9.7460710   9.7460710   9.7460710  11.2419076  10.2337215  10.2337215  10.2337215  10.2337215 
        911         912         913         914         915         916         917         918         919         920 
 10.2337215  10.2337215   9.8390638  10.5285526  10.5285526  10.5285526  10.5285526  10.5285526  10.5285526  10.5285526 
        921         922         923         924         925         926         927         928         929         930 
 10.5285526  13.1310656  10.7216915  10.7216915  10.7216915  10.7216915  10.7216915  10.4102940  10.4102940  10.4102940 
        931         932         933         934         935         936         937         938         939         940 
 20.9218467  10.4102940  10.4102940 100.0000000 100.0000000  10.0866234  10.0866234  10.0866234  10.0866234  10.4927862 
        941         942         943         944         945         946         947         948         949         950 
 10.4927862  10.4927862  10.4927862  10.4927862  10.4927862  10.4927862  10.4389072  10.4389072  10.4389072  10.4389072 
        951         952         953         954         955         956         957         958         959         960 
  9.6459249   9.6459249   9.6459249  10.6000856  59.4499859  10.6000856  10.6000856  10.6000856  10.2752309  10.2752309 
        961         962         963         964         965         966         967         968         969         970 
 10.2752309  10.2752309  10.2752309  10.2752309  60.1683331  10.2752309  11.5972340  12.8954921  10.3481741  10.3481741 
        971         972         973         974         975         976         977         978         979         980 
 10.3481741  10.3481741  10.3481741  10.3481741  10.3481741  10.3481741  10.3481741  11.2428492  11.2428492  11.2428492 
        981         982         983         984         985         986         987         988         989         990 
 11.2428492  10.0599664  10.0599664  10.0599664   9.3231939   9.3231939   9.3231939   9.3231939   9.7389177   9.7389177 
        991         992         993         994         995         996         997         998         999        1000 
  9.7389177   9.3867241  60.6697236   9.3867241   9.3867241   9.3867241   9.3867241   9.2373544   9.2373544   3.5757664 
 [ reached getOption("max.print") -- omitted 1936 entries ]

The take home message from the output is that for every unit increase in the square root of engine displacement there is a -0.14246 decrease in the square root of fuel efficiency (mpg). Therefore, fuel efficiency decreases with increasing engine displacement.

Feauture and coefficients analysis.

coefficients<-coef(ols_ds$finalModel)
coefficients_df <- as.data.frame(coefficients)

features<-rownames(coefficients_df )
coefficients_features <-cbind(coefficients,features)
coefficients_features_df <- as.data.frame(coefficients_features)
 
feature_analysis<-coefficients_features_df %>% 
  select(features,coefficients) %>% 
  filter(!is.na(coefficients)) %>% 
  arrange(desc(coefficients))
feature_analysis
ols_ds$results

See the metrics

actual <- as.vector(testSet$percentage_payment)
actual <- as.data.frame(round(actual,2))
colnames(actual) <- c("actual")
 
predicted <- as.vector(test_pred)
predicted <-as.data.frame(round(predicted,2))
colnames(predicted) <- c("predicted")
library(Metrics)

Attaching package: ‘Metrics’

The following objects are masked from ‘package:caret’:

    precision, recall
#ape computes the elementwise absolute percent difference between two numeric vectors
absolute_percentage_diff<-ape(actual,predicted)
absolute_percentage_diff <-as.data.frame(round(absolute_percentage_diff,2)*100)
colnames(absolute_percentage_diff) <- c("percentage_difference")
actual
#Compare actual y values to predicted values
compare_actuals_to_pred<-cbind(actual,predicted,absolute_percentage_diff,testSet)
compare_actuals_to_pred %>% 
  filter(modality_cost_code_1110==1 & pcn_payer_code_02371001==1) %>% 
  arrange(desc(percentage_difference))

saveRDS(compare_actuals_to_pred,'DCI_Capstone/data/compare_actuals_to_pred.rds')

All features

all_features<-as.data.frame( colnames(compare_actuals_to_pred))
colnames(all_features) = c('features')

all_features 
#modality cost codes
modality_cost_codes<-all_features %>% 
                      filter(features %like% "modality_cost_code_") %>% 
                      arrange(features)
#diagnosis_codes
diagnosis_codes<-all_features %>% 
                filter(features %like% "diagnosis_code_") %>% 
                arrange(features)
#Revenue codes
revenue_codes <-all_features %>% 
                filter(features %like% "revenue_code_") %>% 
                arrange(features)
#modifier_1
modifier_1 <-all_features %>% 
                filter(features %like% "modifier_1_") %>% 
                arrange(features)
 
#Modifier_2
modifier_2 <-all_features %>% 
                filter(features %like% "modifier_2_") %>% 
                arrange(features)
 
#Modifier_3
 modifier_3 <-all_features %>% 
                filter(features %like% "modifier_3_") %>% 
                arrange(features)

#hcpc_code
hcpc_code <-all_features %>% 
                filter(features %like% "hcpc_code_") %>% 
                arrange(features)
#pcn_payor_code 
pcn_payor_code <-all_features %>% 
                filter(features %like% "pcn_payer_code_") %>% 
                arrange(features)
compare_actuals_to_pred %>% 
  filter(pcn_payer_code_02371001 == 1 & modality_cost_code_1110==1) %>% 
  select(pcn_payer_code_02371001,actual,modality_cost_code_1110,predicted,percentage_difference ) %>%
  summarise('avg_actual' = mean(actual),'avg_predicted' = mean(predicted)) %>% 
  pivot_longer(avg_actual:avg_predicted,names_to = "Prediction_type", values_to = "Percentage_values")
pcn_payor_code
modality_cost_codes_shiny
#compare_actuals_to_pred %>% 
trainSet %>% 
  filter(pcn_payer_code_02371001 == 1 & modality_cost_code_1110==1,hcpc_code_90999==1  ) 
trainSet %>% 
  filter(pcn_payer_code_02371001 == 1 & modality_cost_code_1110==1 &hcpc_code_90999==1 )

Bar plots for Actual vs Predicted


compare_actuals_to_pred_plt <-compare_actuals_to_pred %>% 
                              filter(pcn_payer_code_02371001 == 1 & hcpc_code_90999==1 ) %>% 
                              select(actual,predicted,percentage_difference ) %>%
                              summarise('Actual' = mean(actual),'Predicted' = mean(predicted)) %>% 
                              pivot_longer(Actual:Predicted,names_to = "Predictions", values_to = "percentage_predicted") %>% 
                              ggplot(aes(x = Predictions, y = percentage_predicted,fill = Predictions)) +
                              geom_text(aes(label=round(percentage_predicted,2)), vjust=0,size=5) + 
                              geom_col( alpha= 0.7) +
                              scale_fill_manual(values = c("grey","darkslategrey"))+
                              ggtitle("Comparing Actual Payment % to Predicted % For 02371001 and PNEMOVAX") +
                              labs(x = "Actual Vs Predicted", y = "Percentage %")+
                              theme(legend.position = "none")

ggplotly(compare_actuals_to_pred_plt)

NA
compare_actuals_to_pred %>% 
  filter(pcn_payer_code_02371001 == 1  & hcpc_code_90999==1 ) %>% 
   select(actual,predicted,percentage_difference ) %>% 
 pivot_longer(actual:predicted,names_to = "prediction", values_to = "percentage_predicted") %>% 
  ggplot(aes(x = prediction, y = percentage_predicted,fill = prediction)) +
  geom_boxplot(alpha=0.5 ) +
  ggtitle("Comparing Actual Payment % to Predicted %") +
  labs(x = "Actual Vs Predicted", y = "Percentage")

NA

LASSO REGRESSION

#Lasso
sum(is.na(algo_df_final))
[1] 0
library(glmnet)
Loading required package: Matrix

Attaching package: ‘Matrix’

The following objects are masked from ‘package:tidyr’:

    expand, pack, unpack

Loaded glmnet 3.0-1
set.seed(200)
index = createDataPartition(algo_df_final$percentage_payment,p=0.75,list=FALSE)
Error in createDataPartition(algo_df_final$percentage_payment, p = 0.75,  : 
  could not find function "createDataPartition"
test_pred<- predict(lasso_model,newx=x_testTransformed)
MAE(pred=test_pred,obs=y_test)# 2.091932
Error in MAE(pred = test_pred, obs = y_test) : 
  could not find function "MAE"

Compare lasso actual values and predicted values

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVGhpcyBpcyBhbiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2suIFdoZW4geW91IGV4ZWN1dGUgY29kZSB3aXRoaW4gdGhlIG5vdGVib29rLCB0aGUgcmVzdWx0cyBhcHBlYXIgYmVuZWF0aCB0aGUgY29kZS4gCgpUcnkgZXhlY3V0aW5nIHRoaXMgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpSdW4qIGJ1dHRvbiB3aXRoaW4gdGhlIGNodW5rIG9yIGJ5IHBsYWNpbmcgeW91ciBjdXJzb3IgaW5zaWRlIGl0IGFuZCBwcmVzc2luZyAqQ21kK1NoaWZ0K0VudGVyKi4gCgoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocGxvdGx5KQpsaWJyYXJ5KG5hbmlhcikKbGlicmFyeShzY2FsZXMpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2xtbmV0KQpsaWJyYXJ5KGNhcmV0KQpsaWJyYXJ5KHZpcmlkaXMpCmxpYnJhcnkocmVzaGFwZTIpCm9wdGlvbnMoc2NpcGVuID0gOTk5KQpgYGAKCmBgYHtyfQojSW1wb3J0IGRhdGEgZnJvbSBjc3YgYW5kIGNoYW5nZSBkYXRhdHlwZXMgb2YgdGhlIGNvbHVtbnMgZXhjbHVkaW5nIHRoZSBjb2x1bW5zIHdoaWNoIGFyZSBub3QgbmVjZXNzYXJ5CnJhd19kYXRhPC1yZWFkX2NzdignZGF0YS9jYXBzdG9uZV9yZW1pdF9jbGFpbXNfZGF0YS5jc3YnKQogCiNjaG5hZ2UgdGhlIGNvbHVtbnMgZGF0YXR5cGVzIHRvIGNvcnJlY3QgZGF0YSB0eXBlcwpkZjwtcmF3X2RhdGEgJT4lCiAgbXV0YXRlKHBhdGllbnRfaWQgPSBhcy5mYWN0b3IocGF0aWVudF9pZCksCiAgICAgICAgIGxvY2F0aW9uX2lkID0gYXMuZmFjdG9yKGxvY2F0aW9uX2lkKSwKICAgICAgICAgI2Nvc3RfY29kZSA9IGFzLmZhY3Rvcihjb3N0X2NvZGUpLAogICAgICAgICBtb2RhbGl0eV9jb3N0X2NvZGUgPSBhcy5jaGFyYWN0ZXIobW9kYWxpdHlfY29zdF9jb2RlKSwKICAgICAgICAgcmVtaXRfYWxsb3dlZF9hbW91bnQgPSBhcy5kb3VibGUocmVtaXRfYWxsb3dlZF9hbW91bnQpLAogICAgICAgICBjb250cmFjdF9udW1iZXIgPSBhcy5mYWN0b3IoY29udHJhY3RfbnVtYmVyKSwKICAgICAgICAgaGN0X3BlciA9IGFzLmRvdWJsZShoY3RfcGVyKSwKICAgICAgICAgZXBvX3VuaXRzID0gYXMuaW50ZWdlcihlcG9fdW5pdHMpLAogICAgICAgICBwY25fcGF5ZXJfY29kZSA9IGFzLmZhY3RvcihwY25fcGF5ZXJfY29kZSksCiAgICAgICAgIHR5cGVfb2ZfY2FyZSA9IGFzLmZhY3Rvcih0eXBlX29mX2NhcmUpLAogICAgICAgICBkYXRlX29mX3NlcnZpY2UgPSBhcy5EYXRlKGRhdGVfb2Zfc2VydmljZSkKICAgICAgICAgKSAlPiUgCiAgc2VsZWN0KC1lcG9fdW5pdHMsLW1vZGlmaWVyXzQsLW1vZGlmaWVyXzUpCiAKZGY8LWRmICU+JSAKICBtdXRhdGUoJ21vZGFsaXR5JyA9IGNhc2Vfd2hlbihtb2RhbGl0eV9jb3N0X2NvZGUgJWluJSBjKCcxMjIwJywnMTIzMCcsIjExMjEiKSB+ICJQRCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kYWxpdHlfY29zdF9jb2RlICVpbiUgYygnMTExMCcsIjEyMTAiLCIxMzEwIiwiMTUxMCIpIH4gIkhFTU8iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGFsaXR5X2Nvc3RfY29kZSAlaW4lIGMoJzEzMzAnLCIxMzIwIikgfiAiSE9NRSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJPVEhFUlMiKSkKCiAKCmRmPC1kZiAlPiUgcmVwbGFjZV93aXRoX25hIChyZXBsYWNlID0gbGlzdChkaWFnbm9zaXNfY29kZSA9ICdOVUxMJywgdXJyX21vZGlmaWVyID0gJ05VTEwnLG1vZGlmaWVyXzEgPSAnTlVMTCcsbW9kaWZpZXJfMj0nTlVMTCcsbW9kaWZpZXJfMz0nTlVMTCcpKQpkZiA8LSBkZiAlPiUgCiAgICAgIG11dGF0ZSggJ3BlcmNlbnRhZ2VfcGF5bWVudCcgPSAgcmVtaXRfdG90YWxfcGFpZC9yZW1pdF90b3RhbF9jaGFyZ2VkICogMTAwKSAKIAojU0FWRSBEQVRBRlJBTUUKc2F2ZVJEUyhkZiwnY2xlYW5fZGZfZm9yX0VEQS5SRFMnKQoKI3BheW9ycwpwYXlvcnM8LWFzLmRhdGEuZnJhbWUodW5pcXVlKGRmJHBjbl9wYXllcl9jb2RlKSkKY29sbmFtZXMocGF5b3JzKTwtYygicGF5b3JzIikKCnNhdmVSRFMocGF5b3JzLCdEQ0lfY2Fwc3RvbmUvZGF0YS9wYXlvcnMucmRzJykKCgpgYGAKUFJFUEFSRSBBIERBVEFGUkFNRSBXSElDSCBDQU4gQkUgVVNFRCBGT1IgQUxHT1JJVEhNUwpgYGB7cn0KI2RlbGV0ZSB1bm5lY2Vzc2FyeSBjb2x1bW5zCmFsZ29fZGY8LWRmICU+JSAKIHNlbGVjdCAoLWRhdGVfb2Zfc2VydmljZSwtYWNjdF9tbSwtYWNjdF95eXl5LC1jbGFpbV9udW1iZXIsLXJlbWl0X251bWJlciwtbG9jYXRpb25faWQsLXBhdGllbnRfaWQsLWNvbnRyYWN0X251bWJlciwtdXJyX21vZGlmaWVyLC1kZXNjcmlwdGlvbiwtcGVyY2VudGFnZV9wYXltZW50KSAgIAogCiNkdW1taXplIGNhdGVnb3JpY2FsIGNvbHVtbnMKZHVtbXlfY29scyA8LSBjKCJtb2RhbGl0eV9jb3N0X2NvZGUiLCJkaWFnbm9zaXNfY29kZSIsInR5cGVfb2ZfY2FyZSIsInJldmVudWVfY29kZSIsICJtb2RpZmllcl8xIiwibW9kaWZpZXJfMiIsIm1vZGlmaWVyXzMiLCJyZXZlbnVlX2NvZGUiLCJoY3BjX2NvZGUiLCJwY25fcGF5ZXJfY29kZSIpCgphbGdvX2RmPC1mYXN0RHVtbWllczo6ZHVtbXlfY29sdW1ucyhhbGdvX2RmLHNlbGVjdF9jb2x1bW5zID0gYyhkdW1teV9jb2xzKSxpZ25vcmVfbmEgPSBUUlVFKQogCiNyZXBsYWNlIG5hJ3MgdG8gMCdzCmFsZ29fZGZbaXMubmEoYWxnb19kZildPC0gMAoKIAphbGdvX2RmX2ZpbmFsPC1hbGdvX2RmICU+JSAKICAgbXV0YXRlKCAncGVyY2VudGFnZV9wYXltZW50JyA9ICByZW1pdF90b3RhbF9wYWlkL3JlbWl0X3RvdGFsX2NoYXJnZWQgKiAxMDApICU+JSAKICBzZWxlY3QgKC1tb2RhbGl0eV9jb3N0X2NvZGUsLWNvc3RfY29kZSwtZGlhZ25vc2lzX2NvZGUsLXR5cGVfb2ZfY2FyZSwtcmV2ZW51ZV9jb2RlLC1oY3BjX2NvZGUsLW1vZGlmaWVyXzEsLW1vZGlmaWVyXzIsLW1vZGlmaWVyXzMsLXBjbl9wYXllcl9jb2RlLC1yZW1pdF90b3RhbF9jaGFyZ2VkLC1yZW1pdF90b3RhbF9wYWlkLC1yZW1pdHNfdW5pdHMsLXJlbWl0X2FsbG93ZWRfYW1vdW50LC1tb2RhbGl0eSkKCiNTQVZFIERBVEFGUkFNRQpzYXZlUkRTKGFsZ29fZGZfZmluYWwsJ2NsZWFuX2RmX2Zvcl9hbGdvcml0aG0uUkRTJykKYGBgCmBgYHtyfQpzdHIoYWxnb19kZl9maW5hbCkKYGBgCmBgYHtyfQpkZgpgYGAKCmBgYHtyfQojRmluYWwgY2hlY2tzCnN1bShpcy5uYShhbGdvX2RmX2ZpbmFsKSkKYGBgCgpTVU1NQVJZIEFOQUxZU0lTCgpgYGB7cn0KI0NoYXJnZWQKc3VtbWFyeShkZiRyZW1pdF90b3RhbF9jaGFyZ2VkKQpgYGAKYGBge3J9CiNQYWlkCnN1bW1hcnkoZGYkcmVtaXRfdG90YWxfcGFpZCkKYGBgCiAKYGBge3J9CmNoYXJnZXNfZGlzX3BsdDwtZGYgJT4lIAogICAgICAgICAgICAgICAgICBnZ3Bsb3QoYWVzKHg9cmVtaXRfdG90YWxfY2hhcmdlZCwgeSA9IC4uZGVuc2l0eS4uKSkgICsgCiAgICAgICAgICAgICAgICAgIGdlb21faGlzdG9ncmFtKGJyZWFrcyA9IHNlcSgwLDI4MDAsYnk9MTAwICksYmlucyA9IDEwLCBiaW53aWR0aCA9IDAuMDUsCiAgICAgICAgICAgICAgICAgIGZpbGwgPSAgImNoYXJ0cmV1c2U0IiwgYWxwaGEgPSAwLjYpICsKICAgICAgICAgICAgICAgICAgbGFicyh4PSJDaGFyZ2VzIiwgeSA9ICJDb3VudHMiLHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBDaGFyZ2VzIikrCiAgICAgICAgICAgICAgICAgIHRoZW1lX21pbmltYWwoKSsKICAgICAgICAgICAgICAgICAgZ2VvbV9kZW5zaXR5KGNvbG9yID0gInJlZCIsIGFscGhhPTAuNCkrCiAgICAgICAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwxMDAwMCwxMDAwKSkrCiAgICAgICAgICAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMCwzMDAwLDUwMCkpCmdncGxvdGx5KGNoYXJnZXNfZGlzX3BsdCAgKQoKYGBgCmBgYHtyfQpwYXltZW50X2Rpc19wbHQ8LWRmICU+JSAKICAgICAgICAgICAgICBnZ3Bsb3QoYWVzKHg9cmVtaXRfdG90YWxfcGFpZCx5PS4uZGVuc2l0eS4uKSkgICsgCiAgICAgICAgICAgICAgZ2VvbV9oaXN0b2dyYW0oYnJlYWtzID0gc2VxKDAsMjgwMCxieT0xMDAgKSxiaW5zID0gMTAsIGJpbndpZHRoID0gMC4wNSwKICAgICAgICAgICAgICAgICBmaWxsID0gICJjaGFydHJldXNlNCIsIGFscGhhID0gMC42KSArCiAgICAgICAgICAgICAgICAgbGFicyh4PSJQYXltZW50cyIsIHkgPSAiQ291bnRzIix0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgUGF5bWVudHMiKSsKICAgICAgICAgICAgICAgICB0aGVtZV9taW5pbWFsKCkrCiAgICAgICAgICAgICAgICAgZ2VvbV9kZW5zaXR5KGNvbG9yID0gInJlZCIsYWxwaGEgPSAwLjQpKwogICAgICAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwxMDAwMCwxMDAwKSkrCiAgICAgICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsMzAwMCw1MDApKQpnZ3Bsb3RseShwYXltZW50X2Rpc19wbHQgICkKYGBgCgoKYGBge3J9CnBsPC0gZ2dwbG90KGRmLGFlcyh4PXJlbWl0X3RvdGFsX2NoYXJnZWQseT1yZW1pdF90b3RhbF9wYWlkKSApKwogIGdlb21fcG9pbnQoYWxwaGE9IDAuNykrCiAgZ2dwbG90bHkocGwpCmBgYAoKYGBge3J9CiAKZGNpX2RhdGFfdG90YWw8LWRmICU+JSAKICAgICAgICAgICAgZmlsdGVyKGFjY3RfeXl5eSA9PSAyMDE3KSAlPiUgCiAgICAgICAgICAgIHNlbGVjdCgnQ2hhcmdlcycgPSByZW1pdF90b3RhbF9jaGFyZ2VkLCdQYXltZW50cyc9cmVtaXRfdG90YWxfcGFpZCkKCmRjaV9sb25nIDwtIHJlc2hhcGUyOjptZWx0KGRjaV9kYXRhX3RvdGFsKQoKI3NhdmVSRFMoZGNpX2xvbmcsJ2Rpc3RfcGx0cy5yZHMnKQoKZGlzdF9wbHRzPC1nZ3Bsb3QoZGNpX2xvbmcsIGFlcyh2YWx1ZSx5ID0gLi5kZW5zaXR5Li4pKSArIGZhY2V0X3dyYXAofnZhcmlhYmxlLCBzY2FsZXMgPSAnZnJlZV94JykgKwogICAgICAgICAgIGdlb21fZGVuc2l0eShjb2xvciA9ICJyZWQiLGFscGhhID0gMC40KSsKICAgICAgICAgICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1dGlvbiIpKwogICAgICAgICAgIGdlb21faGlzdG9ncmFtKCBmaWxsID0gICJjaGFydHJldXNlNCIsIGFscGhhID0gMC42KSsKICMgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IG1lYW4odmFsdWUsbmEucm09VCkpLGNvbG9yID0gInJlZCIsIGxpbmV0eXBlID0gImRhc2hlZCIsc2l6ZSA9IDEpICsKICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsMTAwMDAsMTAwMCkpKwogICAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMCwzMDAwLDUwMCkpCgpkaXN0X3BsdHMKYGBgCgoKYGBge3J9CmRmICU+JSAKICBnZ3Bsb3QoYWVzKHg9cmVtaXRfdG90YWxfcGFpZCkpICsgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSA1MCkKYGBgCgogCmBgYHtyfQpkZiAlPiUgCiAgZ2dwbG90KGFlcyh4PXJlbWl0X3RvdGFsX3BhaWQsZmlsbCA9IG1vZGFsaXR5KSkgKyAKICAgIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSBtZWFuKHJlbWl0X3RvdGFsX3BhaWQsbmEucm09VCkpLGNvbG9yID0gInJlZCIsIGxpbmV0eXBlID0gImRhc2hlZCIsc2l6ZSA9IDEpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zPTQwLGJpbndpZHRoID0gMTAsIGNlbnRlciA9IDAuMDUsYWxwaGEgPSAwLjgpCmBgYApgYGB7cn0KY2JwMSA8LSBjKCIjOTk5OTk5IiwgIiNFNjlGMDAiLCAiIzU2QjRFOSIsICIjMDA5RTczIiwKICAgICAgICAgICIjRjBFNDQyIiwgIiMwMDcyQjIiLCAiI0Q1NUUwMCIsICIjQ0M3OUE3IikKZGlzdF9ib3hfbW9kYWxpdHk8LWRmICU+JSAKICAgICAgICAgICAgICAgICAgZmlsdGVyKGFjY3RfeXl5eSA9PSAyMDE3KSAlPiUgCiAgICAgICAgICAgICAgICAgIHNlbGVjdChtb2RhbGl0eSxyZW1pdF90b3RhbF9wYWlkKSAlPiUgCiAgICAgICAgICAgICAgICAgIGdncGxvdChhZXMoICBtb2RhbGl0eSwgcmVtaXRfdG90YWxfcGFpZCxhbHBoYSA9IDAuNSkpICsKICAgICAgICAgICAgICAgICAgZ2VvbV9ib3hwbG90KGFlcyhmaWxsPW1vZGFsaXR5KSkgKwogICAgICAgICAgICAgICAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgICAgICAgICAgICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjYnAxKSArCiAgICAgICAgICAgICAgICAgIGdndGl0bGUoIkRpc3RyaWJ1dGlvbiBvZiBQYXltZW50cyBhY3Jvc3MgTW9kYWxpdGllcyIpICsKICAgICAgICAgICAgICAgICAgbGFicyh4PSJNb2RhbGl0eSIseSA9ICJQYXltZW50cyIpICArCiAgICAgICAgICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKZ2dwbG90bHkoZGlzdF9ib3hfbW9kYWxpdHkpCiAgCmBgYApgYGB7cn0KcGF5b3JzCmBgYApgYGB7cn0KcGF5b3JzCmBgYApgYGB7cn0KZGYgJT4lIAogICAgICAgICAgICAgICAgICAgICAgIyBmaWx0ZXIocGNuX3BheWVyX2NvZGUgPT0nMjQxODA0MDInKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAjZmlsdGVyKG1vZGFsaXR5ID09ICdQRCcpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICBncm91cF9ieShtb2RhbGl0eSxwY25fcGF5ZXJfY29kZSkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZShzdW1fcGF5bWVudHM9IHN1bShyZW1pdF90b3RhbF9wYWlkKSkKYGBgCgoKYGBge3J9CgogCnRvdGFsX3BheW1lbnRzX2Jhcl9wbHQ8LWRmICU+JSAKICAgICAgICAgICAgICAgICAgICAgICMgZmlsdGVyKHBjbl9wYXllcl9jb2RlID09JzI0MTgwNDAyJykgJT4lIAogICAgICAgICAgICAgICAgICAgICAgI2ZpbHRlcihtb2RhbGl0eSA9PSAnUEQnKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkobW9kYWxpdHkpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICBzdW1tYXJpc2Uoc3VtX3BheW1lbnRzPSBzdW0ocmVtaXRfdG90YWxfcGFpZCkpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICBnZ3Bsb3QoYWVzKHggPSBtb2RhbGl0eSwgeSA9IHN1bV9wYXltZW50cywgZmlsbCA9IG1vZGFsaXR5KSkgKwogICAgICAgICAgICAgICAgICAgICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBhbHBoYT0wLjgpICsKICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgICAgICAgICAgICAgICAgICAgIGxhYnMoCiAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9ICJNb2RhbGl0eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9ICJUb3RhbCBQYXltZW50cyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSAiVG90YWwgUGF5bWVudHMgYnkgTW9kYWxpdHkiCiAgICAgICAgICAgICAgICAgICAgICAgICAgKSArCiAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjYnAxKSArCiAgICAgICAgICAgICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgogICAgZ2dwbG90bHkodG90YWxfcGF5bWVudHNfYmFyX3BsdCkKYGBgCgoKRU5EIE9GIFNVTU1BUlkgQU5BTFlTSVMKCkJFR0lOIFRJTUUgU0VSSVMgQU5BTFlTSVMKIApgYGB7cn0KIGF2Z19wY3RfcGFpZF9vdmVyX3RpbWU8LWRmICU+JSAKICBmaWx0ZXIoYWNjdF95eXl5ID09IDIwMTgpICU+JSAKICBtdXRhdGUoJ3BlcmNlbnRhZ2VfcGFpZCcgPSByZW1pdF90b3RhbF9wYWlkL3JlbWl0X3RvdGFsX2NoYXJnZWQqMTAwKSAlPiUgCiAgbXV0YXRlKCdwZXJpb2QnID0gIHBhc3RlKGFjY3RfbW0gLCAnLycgLCBhY2N0X3l5eXkpKSAlPiUgCiAgc2VsZWN0KGFjY3RfbW0sYWNjdF95eXl5LHBlcmlvZCxwZXJjZW50YWdlX3BhaWQscGNuX3BheWVyX2NvZGUpICU+JSAKICBncm91cF9ieShhY2N0X21tLHBlcmlvZCxwY25fcGF5ZXJfY29kZSkgJT4lIAogIHN1bW1hcmlzZSgnYXZnX3BjdF9wYWlkJz1tZWFuKHBlcmNlbnRhZ2VfcGFpZCkpICAKCnRpbWVfcGxvdDwtZ2dwbG90KGF2Z19wY3RfcGFpZF9vdmVyX3RpbWUsIGFlcyggcmVvcmRlcihwZXJpb2QsYWNjdF9tbSkgLCBhdmdfcGN0X3BhaWQsIGdyb3VwID0gcGNuX3BheWVyX2NvZGUsIGNvbG9yID0gcGNuX3BheWVyX2NvZGUpKSArIAogIGdlb21fbGluZShzaXplID0gMSkgKwogIGdlb21fcG9pbnQoc2l6ZT0yLCBzaGFwZT02LCBhZXMoZmlsbD1mYWN0b3IocGNuX3BheWVyX2NvZGUpKSkgKwogIHRoZW1lX21pbmltYWwoKSsKICBsYWJzKGNvbG9yID0gIlBheW9ycyIsIGZpbGwgPSAnUGF5b3JzJykrCiAgeWxhYignUGVyY2VudGFnZSBvZiBQYXltZW50cyAnKSArCiAgeGxhYignTW9udGgvWWVhcicpICsKICB5bGltKDAsIDUwKSsKICBnZ3RpdGxlKCdQZXJjZW50YWdlIG9mIFBheW1lbnRzIGJ5IFBheW9yIG92ZXIgdGltZScpKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLGhqdXN0PTEpKQoKZ2dwbG90bHkodGltZV9wbG90KQpgYGAKCmBgYHtyfQogZGYgJT4lIAogIGZpbHRlcihhY2N0X3l5eXkgPT0gMjAxOCkgJT4lIAogIG11dGF0ZSgncGVyY2VudGFnZV9wYWlkJyA9IHJlbWl0X3RvdGFsX3BhaWQvcmVtaXRfdG90YWxfY2hhcmdlZCoxMDApICU+JSAKICBtdXRhdGUoJ3BlcmlvZCcgPSAgcGFzdGUoYWNjdF9tbSAsICcvJyAsIGFjY3RfeXl5eSkpICU+JSAKICBzZWxlY3QoYWNjdF9tbSxhY2N0X3l5eXkscGVyaW9kLHBlcmNlbnRhZ2VfcGFpZCxwY25fcGF5ZXJfY29kZSkgJT4lIAogIGdyb3VwX2J5KGFjY3RfbW0sYWNjdF95eXl5LHBlcmlvZCxwY25fcGF5ZXJfY29kZSkgJT4lIAogIHN1bW1hcmlzZSgnYXZnX3BjdF9wYWlkJz1tZWFuKHBlcmNlbnRhZ2VfcGFpZCkpICU+JSAKICBhcnJhbmdlKGFjY3RfbW0sYXZnX3BjdF9wYWlkKSAlPiUgCiAgZ2dwbG90KGFlcyggcmVvcmRlcih4ID0gcGVyaW9kLGFjY3RfbW0pICx5ID0gYXZnX3BjdF9wYWlkLGdyb3VwPTEsY29sb3I9cGNuX3BheWVyX2NvZGUsZmlsbD1wY25fcGF5ZXJfY29kZSkpICsgCiAgZ2VvbV9wb2ludCgpICsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsaGp1c3Q9MSkpCgpgYGAKIAogQU5BTFlTSVMgQlkgTE9DQVRJT04gKGNhbiBiZSBhIHBhZ2UpCmBgYHtyfQojIHBheW1lbnQgcGVyY2VudGFnZSBieSBsb2NhdGlvbgpkZiAlPiUgCiAgZ3JvdXBfYnkobG9jYXRpb25faWQpICU+JSAKICBzdW1tYXJpc2UoJ051bV9vZl9yb3dzJz1uKCksCiAgICAgICAgICAgICdUb3RhbF9jaGFyZ2VzJyA9IHN1bShyZW1pdF90b3RhbF9jaGFyZ2VkKSwKICAgICAgICAgICAgJ1RvdGFsX3BheW1lbnRzJyA9IHN1bShyZW1pdF90b3RhbF9wYWlkKSwKICAgICAgICAgICAgJ3BlcmNlbnRhZ2VfcGF5bWVudHMnID0gKFRvdGFsX3BheW1lbnRzL1RvdGFsX2NoYXJnZXMpICogMTAwLAogICAgICAgICAgICApICU+JSAKICBhcnJhbmdlKGRlc2MoVG90YWxfY2hhcmdlcykpCgpgYGAKQUxBTllTSVMgIEJZIFBDTiAoUEFZT1JTKQpgYGB7cn0KCiMgcGF5bWVudCBwZXJjZW50YWdlIGJ5IFBDTgpjaGFyZ2VfcGF5bWVudHM8LSBkZiAlPiUgCiAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KHBjbl9wYXllcl9jb2RlKSAlPiUgCiAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZSgnTnVtX29mX3Jvd3MnPW4oKSwKICAgICAgICAgICAgICAgICAgICdUb3RhbF9jaGFyZ2VzJyA9IHN1bShyZW1pdF90b3RhbF9jaGFyZ2VkKSwKICAgICAgICAgICAgICAgICAgICAnVG90YWxfcGF5bWVudHMnID0gc3VtKHJlbWl0X3RvdGFsX3BhaWQpLAogICAgICAgICAgICAgICAgICAgICAncGVyY2VudGFnZV9wYXltZW50cycgPSAoVG90YWxfcGF5bWVudHMvVG90YWxfY2hhcmdlcykgKiAxMDAsCiAgICAgICAgICAgICAgICAgICAgICApICU+JSAKICAgICAgICAgICAgICAgICAgYXJyYW5nZShwZXJjZW50YWdlX3BheW1lbnRzKQpgYGAKYGBge3J9CmNoYXJnZV9wYXltZW50cyAlPiUgCiAgbXV0YXRlKCdtZWFuX3BlcmNlbnRhZ2VfcGF5bWVudHMnID0gc3VtKFRvdGFsX3BheW1lbnRzKS9zdW0oVG90YWxfY2hhcmdlcykqMTAwKSAlPiUgCiAgbXV0YXRlKCdkaXNfZnJvbV9hdmdfcGVyX3BheW1lbnQnID0gIHBlcmNlbnRhZ2VfcGF5bWVudHMtbWVhbl9wZXJjZW50YWdlX3BheW1lbnRzICkKYGBgCmBgYHtyfQpwYXlvcnNfd2l0aF9nb29kX3BlcjwtZGYgJT4lIAogICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkocGNuX3BheWVyX2NvZGUpICU+JSAKICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZSgnTnVtX29mX3Jvd3MnPW4oKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnVG90YWxfY2hhcmdlcycgPSBzdW0ocmVtaXRfdG90YWxfY2hhcmdlZCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1RvdGFsX3BheW1lbnRzJyA9IHN1bShyZW1pdF90b3RhbF9wYWlkKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAncGVyY2VudGFnZV9wYXltZW50cycgPSAoVG90YWxfcGF5bWVudHMvVG90YWxfY2hhcmdlcykgKiAxMDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBhcnJhbmdlKGRlc2MoVG90YWxfY2hhcmdlcykpICU+JSAKICAgICAgICAgICAgICAgICAgICAgIGdncGxvdChhZXMocmVvcmRlcih4PXBjbl9wYXllcl9jb2RlLHBlcmNlbnRhZ2VfcGF5bWVudHMpLHk9cGVyY2VudGFnZV9wYXltZW50cyxmaWxsID0gcGNuX3BheWVyX2NvZGUpKSArCiAgICAgICAgICAgICAgICAgICAgICBnZW9tX2NvbChhbHBoYT0wLjgpICsKICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX21pbmltYWwoKSsKICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsaGp1c3Q9MSkpKwogICAgICAgICAgICAgICAgICAgICAgbGFicyh4PSdQYXlvcnMnLHk9IlBlcmNlbnRhZ2Ugb2YgY2hhcmdlcyBwYWlkIix0aXRsZSA9ICJXaGljaCBwYXlvcnMgYXJlIHBheWluZyBnb29kIHBlcmNlbnRhZ2U/IikKCmdncGxvdGx5KHBheW9yc193aXRoX2dvb2RfcGVyKQoKYGBgCiNXaGljaCBwYXllciBpcyBwYXlpbmcgZ29vZCBwZXJjZW50YWdlIGJ5IG1vZGFsaXR5CmBgYHtyfQpkZiAlPiUgZ3JvdXBfYnkocGNuX3BheWVyX2NvZGUsbW9kYWxpdHkpICU+JSAKICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZSgnTnVtX29mX3Jvd3MnPW4oKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnVG90YWxfY2hhcmdlcycgPSBzdW0ocmVtaXRfdG90YWxfY2hhcmdlZCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1RvdGFsX3BheW1lbnRzJyA9IHN1bShyZW1pdF90b3RhbF9wYWlkKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAncGVyY2VudGFnZV9wYXltZW50cycgPSAoVG90YWxfcGF5bWVudHMvVG90YWxfY2hhcmdlcykgKiAxMDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBhcnJhbmdlKGRlc2MoVG90YWxfY2hhcmdlcykpCmBgYAoKYGBge3J9CiBwYXlvcnNfd2l0aF9nb29kX3BlcjwtZGYgJT4lIGdyb3VwX2J5KHBjbl9wYXllcl9jb2RlLG1vZGFsaXR5KSAlPiUgCiAgZmlsdGVyKHBjbl9wYXllcl9jb2RlPT0nMDIzNzEwMDEnKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBzdW1tYXJpc2UoJ051bV9vZl9yb3dzJz1uKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1RvdGFsX2NoYXJnZXMnID0gc3VtKHJlbWl0X3RvdGFsX2NoYXJnZWQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdUb3RhbF9wYXltZW50cycgPSBzdW0ocmVtaXRfdG90YWxfcGFpZCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ3BlcmNlbnRhZ2VfcGF5bWVudHMnID0gcm91bmQoKFRvdGFsX3BheW1lbnRzL1RvdGFsX2NoYXJnZXMpICogMTAwLDIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBhcnJhbmdlKGRlc2MoVG90YWxfY2hhcmdlcykpICU+JSAKICAgICAgICAgICAgICAgICAgICAgIGdncGxvdChhZXMocmVvcmRlcih4PW1vZGFsaXR5LHBlcmNlbnRhZ2VfcGF5bWVudHMpLHk9cGVyY2VudGFnZV9wYXltZW50cyxmaWxsID0gbW9kYWxpdHkpKSArCiAgICAgICAgICAgICAgICAgICAgICBnZW9tX2NvbChhbHBoYT0wLjgpICsKICAgICAgICAgICAgICAgICAgICAgIGdlb21fdGV4dChhZXMobGFiZWw9cGVyY2VudGFnZV9wYXltZW50cyksIHZqdXN0PTApICsgCiAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9taW5pbWFsKCkrCiAgICAgICAgICAgICAgICAgICAgICBsYWJzKHg9J01vZGFsaXR5Jyx5PSJQZXJjZW50YWdlIG9mIGNoYXJnZXMgcGFpZCIsdGl0bGUgPSAiUGVyY2VudGFnZSBvZiBDaGFyZ2VzIHBhaWQgYnkgTW9kYWxpdHk/IikrCiAgICAgICAgICAgICAgICAgICAgICB0aGVtZSggdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSkKCmdncGxvdGx5KHBheW9yc193aXRoX2dvb2RfcGVyKQpgYGAKYGBge3J9CmRmICAKCiAgCmBgYAoKIApgYGB7cn0KIHBheW9yc193aXRoX2dvb2RfcGVyPC1kZiAlPiUgZ3JvdXBfYnkocGNuX3BheWVyX2NvZGUsbW9kYWxpdHkpICU+JSAKICBmaWx0ZXIocGNuX3BheWVyX2NvZGU9PScwMjM3MTAwMScpICU+JSAKICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZSgnTnVtX29mX3Jvd3MnPW4oKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnVG90YWxfY2hhcmdlcycgPSBzdW0ocmVtaXRfdG90YWxfY2hhcmdlZCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1RvdGFsX3BheW1lbnRzJyA9IHN1bShyZW1pdF90b3RhbF9wYWlkKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAncGVyY2VudGFnZV9wYXltZW50cycgPSByb3VuZCgoVG90YWxfcGF5bWVudHMvVG90YWxfY2hhcmdlcykgKiAxMDAsMikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JSAKICAgICAgICAgICAgICAgICAgICAgIGFycmFuZ2UoZGVzYyhUb3RhbF9jaGFyZ2VzKSkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgZ2dwbG90KGFlcyhyZW9yZGVyKHg9bW9kYWxpdHkscGVyY2VudGFnZV9wYXltZW50cykseT1wZXJjZW50YWdlX3BheW1lbnRzLGZpbGwgPSBtb2RhbGl0eSkpICsKICAgICAgICAgICAgICAgICAgICAgIGdlb21fc2VnbWVudChhZXMgKHJlb3JkZXIoeD1tb2RhbGl0eSxwZXJjZW50YWdlX3BheW1lbnRzKSwgeGVuZCA9bW9kYWxpdHkseT0wLHllbmQgPSBwZXJjZW50YWdlX3BheW1lbnRzKSApKwogICAgICAgICAgICAgICAgICAgICAgZ2VvbV9wb2ludChjb2xvciA9ICJvcmFuZ2UiLHNpemUgPSA0KSsKICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX21pbmltYWwoKSsKICAgIGdlb21fdGV4dChhZXMobGFiZWw9cGVyY2VudGFnZV9wYXltZW50cykpICsgIAogICAgICAgICAgICAgICAgICAgICAgbGFicyh4PSdNb2RhbGl0eScseT0iUGVyY2VudGFnZSBvZiBDaGFyZ2VzIFBhaWQoJSkiLHRpdGxlID0gIlBlcmNlbnRhZ2Ugb2YgQ2hhcmdlcyBQYWlkIGJ5IE1vZGFsaXR5PyIpKwogICAgICAgICAgICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDIwLDEpKSsKICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKICAKCmdncGxvdGx5KHBheW9yc193aXRoX2dvb2RfcGVyKQpgYGAKIAoKCkJZIExPQ0FJVE9OLCBXSElDSCBQQVlPUlMgQVJFIENPTlRSSUJVVElORyBNT1JFIChDQU4gQkUgQSBUQUIpCmBgYHtyfQpkZiAlPiUgCiAgZ3JvdXBfYnkobG9jYXRpb25faWQscGNuX3BheWVyX2NvZGUpICU+JSAKICBzdW1tYXJpc2UoJ3RvdGFsX2NoYXJnZXMnPXN1bShyZW1pdF90b3RhbF9jaGFyZ2VkKSwndG90YWxfcGFpZCcgPSBzdW0ocmVtaXRfdG90YWxfcGFpZCkpICU+JSAKICBtdXRhdGUoJ2xvc3NfYW10JyA9IHRvdGFsX2NoYXJnZXMtdG90YWxfcGFpZCkgJT4lIAogIG11dGF0ZSgncGF5bWVudF9wZXJjZW50YWdlJyA9ICh0b3RhbF9wYWlkL3RvdGFsX2NoYXJnZXMpKjEwMCkgJT4lIAogIG11dGF0ZSgnbG9zc19wZXJjZW50YWdlJyA9IChsb3NzX2FtdC90b3RhbF9jaGFyZ2VzKSAqIDEwMCkgJT4lIAogIGZpbHRlcih0b3RhbF9wYWlkIT0wKSAlPiUgCiAgYXJyYW5nZShsb2NhdGlvbl9pZCxkZXNjKHBheW1lbnRfcGVyY2VudGFnZSkpCmBgYAoKYGBge3J9CnVuaXF1ZShkZiRwY25fcGF5ZXJfY29kZSkKYGBgCmBgYHtyfQpjb2xuYW1lcyhkZikKYGBgCgpgYGB7cn0KZGlzdGluY3QoZGYsYWNjdF95eXl5LHBjbl9wYXllcl9jb2RlICkgJT4lIAogIGZpbHRlcihhY2N0X3l5eXk9PTIwMTgpIApgYGAKCmBgYHtyfQojdW5pcXVlKGRmJHBjbl9wYXllcl9jb2RlKQpkZiU+JSAKICAgICAgICAgICAgICAgIGdyb3VwX2J5KGRlc2NyaXB0aW9uKSAlPiUgCiAgICAgICAgICAgICAgICBmaWx0ZXIgKHBjbl9wYXllcl9jb2RlID09JzAwNDEwMjM1JykgJT4lIAogICAgICAgICAgICAgICBzdW1tYXJpc2UoJ3RvdGFsX2NoYXJnZXMnPXN1bShyZW1pdF90b3RhbF9jaGFyZ2VkKSwndG90YWxfcGFpZCcgPSBzdW0ocmVtaXRfdG90YWxfcGFpZCkpICU+JSAKICAgICAgICAgICAgICAgIG11dGF0ZSgncGVyY2VudGFnZV9vZl9wYXltZW50cycgPSByb3VuZCh0b3RhbF9wYWlkL3RvdGFsX2NoYXJnZXMqMTAwLDIpKSAlPiUgCiAgICAgICAgICAgICAgICBtdXRhdGUoJ3Blcl9wYXltZW50X292ZXJhbGwnID0gcm91bmQoKHRvdGFsX3BhaWQvc3VtKHRvdGFsX3BhaWQpKSoxMDAsMikpIAogICAgICAgICAgICAgICAgI2ZpbHRlcih0b3RhbF9wYWlkPjApCmBgYAoKU2VydmljZXMgYnkgZWFjaCBwYXlvciB0eXBlCmBgYHtyfQpzZXJ2aWNlc19wbHQgPC0gZGYlPiUgCiAgICAgICAgICAgICAgICBncm91cF9ieShkZXNjcmlwdGlvbikgJT4lIAogICAgICAgICAgICAgICAgZmlsdGVyIChwY25fcGF5ZXJfY29kZSA9PScwMjM3MTAwMScpICU+JSAKICAgICAgICAgICAgICAgc3VtbWFyaXNlKCd0b3RhbF9jaGFyZ2VzJz1zdW0ocmVtaXRfdG90YWxfY2hhcmdlZCksJ3RvdGFsX3BhaWQnID0gc3VtKHJlbWl0X3RvdGFsX3BhaWQpKSAlPiUgCiAgICAgICAgICAgICAgICBtdXRhdGUoJ3BlcmNlbnRhZ2Vfb2ZfcGF5bWVudHMnID0gcm91bmQodG90YWxfcGFpZC90b3RhbF9jaGFyZ2VzKjEwMCwyKSkgJT4lIAogICAgICAgICAgICAgICAgbXV0YXRlKCdwZXJfcGF5bWVudF9vdmVyYWxsJyA9IHJvdW5kKCh0b3RhbF9wYWlkL3N1bSh0b3RhbF9wYWlkKSkqMTAwLDIpKSAlPiUgCiAgICAgICAgICAgICAgICBmaWx0ZXIodG90YWxfcGFpZD4wKSAlPiUgCiAgICAgICAgICAgICAgICBnZ3Bsb3QoYWVzKHJlb3JkZXIoeD0gZGVzY3JpcHRpb24sdG90YWxfcGFpZCkseSA9IHRvdGFsX3BhaWQsZmlsbCA9IGRlc2NyaXB0aW9uKSkgKwogICAgICAgICAgICAgICAgZ2VvbV9jb2woKSsKICAgICAgICAgICAgICAgIGNvb3JkX2ZsaXAoKSsKICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsaGp1c3Q9MSkpICsKICAgICAgICAgICAgICAgIHRoZW1lX21pbmltYWwoKSsKICAgICAgICAgICAgICAgIHhsYWIoIlNlcnZpY2VzIikgKwogICAgICAgICAgICAgICAgeWxhYigiUGF5bWVudHMiKSArCiAgICAgICAgICAgICAgICBnZ3RpdGxlKCJUb3RhbCBQYXltZW50cyBieSBTZXJ2aWNlcyIpKwogICAgICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSAKCmdncGxvdGx5KHNlcnZpY2VzX3BsdCkKYGBgCgoKRk9SIFdIQVQgVFlQRSBPRiBUUkVBVE1FTlQgLyBNRURJQ0FUSU9OIEFSRSBXRSBHRVRUSU5HIFBBSUQgTEVTUyAvIE1PUkUgVEhBTiAxMCBQRVJDRU5UIChDQU4gQkUgQSBQQUdFKQpgYGB7cn0KeDwtIGRmICU+JSAKICAgICAgZ3JvdXBfYnkoJ0Rlc2NyaXB0aW9uJz1kZXNjcmlwdGlvbikgJT4lIAogICAgICBzdW1tYXJpc2UoJ3RvdGFsX2NoYXJnZXMnPXN1bShyZW1pdF90b3RhbF9jaGFyZ2VkKSwKICAgICAgJ3RvdGFsX3BhaWQnID0gc3VtKHJlbWl0X3RvdGFsX3BhaWQpKSAlPiUgCiAgICAgIG11dGF0ZSgncGVyY2VudGFnZV9wYWlkJyA9IHJvdW5kKHRvdGFsX3BhaWQvdG90YWxfY2hhcmdlcyAqIDEwMCwyKSkgJT4lIAogICAgICBhcnJhbmdlKGRlc2MocGVyY2VudGFnZV9wYWlkKSAgKQoKc2F2ZVJEUyh4JERlc2NyaXB0aW9uLCdkYXRhL21lZHMucmRzJykKYGBgCmBgYHtyfQpkZiAlPiUgCiAgZmlsdGVyKGRlc2NyaXB0aW9uID09ICdBUkFORVNQL0RBUkJFUE9FVElOIEFMRkEtJyApICU+JSAgIAogIGdyb3VwX2J5KGRlc2NyaXB0aW9uKSAlPiUgCiAgc3VtbWFyaXNlKCdUb3RhbENoYXJnZXMnPXN1bShyZW1pdF90b3RhbF9jaGFyZ2VkKSwnVG90YWxQYWlkJyA9IHN1bShyZW1pdF90b3RhbF9wYWlkKSkgJT4lIAogcGl2b3RfbG9uZ2VyKFRvdGFsQ2hhcmdlczpUb3RhbFBhaWQsbmFtZXNfdG8gPSAiVHlwZSIsIHZhbHVlc190byA9ICJDaGFyZ2VzIikKYGBgCgpgYGB7cn0KI3doYXQgcGVyY2VudGFnZSBhcmUgd2UgcGFpZCBiYWNrIG92ZXJhbGwgZm9yIGEgZGVzY3JpcHRpb24KIGRmICU+JSAKICAgICAgZ3JvdXBfYnkoJ0Rlc2NyaXB0aW9uJz1kZXNjcmlwdGlvbikgJT4lIAogICAgICBzdW1tYXJpc2UoJ3RvdGFsX2NoYXJnZXMnPXN1bShyZW1pdF90b3RhbF9jaGFyZ2VkKSwndG90YWxfcGFpZCcgPSBzdW0ocmVtaXRfdG90YWxfcGFpZCkpICU+JSAKICAgICAgbXV0YXRlKCdwZXJjZW50YWdlJyA9IHJvdW5kKHRvdGFsX3BhaWQvdG90YWxfY2hhcmdlcyAqIDEwMCwyKSkgJT4lIAogICAgICBzZWxlY3QgKERlc2NyaXB0aW9uLHBlcmNlbnRhZ2UpIApgYGAKCgpNZWRpY2F0aW9ucyBmb3Igd2hpY2ggbGVzcyB0aGFuIDEwIHBlcmNlbnQgcGFpZApgYGB7cn0KIyN0b3AgY29zdCBjb2RlcwptZWRzPC1kZiAlPiUgCiAgZmlsdGVyKGRlc2NyaXB0aW9uID09ICdBUkFORVNQL0RBUkJFUE9FVElOIEFMRkEtJyApICU+JSAgIAogIGdyb3VwX2J5KGRlc2NyaXB0aW9uKSAlPiUgCiAgc3VtbWFyaXNlKCdUb3RhbENoYXJnZXMnPXN1bShyZW1pdF90b3RhbF9jaGFyZ2VkKSwnVG90YWxQYWlkJyA9IHN1bShyZW1pdF90b3RhbF9wYWlkKSkgJT4lIAogcGl2b3RfbG9uZ2VyKFRvdGFsQ2hhcmdlczpUb3RhbFBhaWQsbmFtZXNfdG8gPSAiVHlwZSIsIHZhbHVlc190byA9ICJDaGFyZ2VzIiklPiUKICBnZ3Bsb3QoYWVzKHg9cmVvcmRlcihkZXNjcmlwdGlvbixDaGFyZ2VzKSx5PUNoYXJnZXMsZmlsbCA9IFR5cGUpICkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IixhbHBoYSA9IDAuOCxwb3NpdGlvbiA9ICdkb2RnZScpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LGhqdXN0PTEpKSArCiAgdGhlbWVfbWluaW1hbCgpKwogIHhsYWIoIk1lZGljYXRpb24iKSArCiAgeWxhYigiRG9sbGFycyIpICsKICBnZ3RpdGxlKCJUb3RhbCBDaGFyZ2VzIHZzIFRvdGFsIFBhaWQiKSAKCmdncGxvdGx5KG1lZHMpCmBgYAogCiAgCiAgCgoKCiAKYGBge3J9Cm1lZHMlPiUgCiAgICAgIGFycmFuZ2UoZGVzYyhhdmdfcGVyX3BhaWQpKQpgYGAKIApEaWZmZXJlbmNlIGluIHBheW1lbnRzIGJ5IG1vZGFsaXR5IG9uIG1lZGljYXRpb25zCmBgYHtyfQojb25seSBtZWRpY2F0aW9ucyBwYWlkIGJ5IGNvc3RfY29kZQptZWRzPC0gZGYgJT4lIAogICAgICBzZWxlY3QobW9kYWxpdHlfY29zdF9jb2RlLGNvc3RfY29kZSxkZXNjcmlwdGlvbixyZW1pdF90b3RhbF9jaGFyZ2VkLHJlbWl0X3RvdGFsX3BhaWQsbW9kYWxpdHkpICU+JSAKICAgICAgZmlsdGVyKGNvc3RfY29kZT4zMDAwICkgJT4lICAKICAgICAgbXV0YXRlKCdwZXJjZW50YWdlX3BhaWQnID0gcm91bmQocmVtaXRfdG90YWxfcGFpZC9yZW1pdF90b3RhbF9jaGFyZ2VkICogMTAwLDIpKSAlPiUgCiAgICAgZ3JvdXBfYnkobW9kYWxpdHksIGRlc2NyaXB0aW9uKSAlPiUgCiAgICBzdW1tYXJpemUoJ2F2Z19wZXJfcGFpZCc9bWVhbihwZXJjZW50YWdlX3BhaWQpKSAgCgptZWRzPC0gbWVkcyU+JSAKICAgICAgZmlsdGVyKGF2Z19wZXJfcGFpZCA8NTQpCgpvcHRpb25zKHJlcHIucGxvdC53aWR0aCA9IDMsIHJlcHIucGxvdC5oZWlnaHQgPSAzKQoKIHg8LSBnZ3Bsb3QobWVkcyxhZXMocmVvcmRlcih4PWRlc2NyaXB0aW9uLGF2Z19wZXJfcGFpZCksIHkgPSBhdmdfcGVyX3BhaWQsZmlsbCA9ICBtb2RhbGl0eSApKSArCiAgZ2VvbV9jb2woc3RhdD0iaWRlbnRpdHkiLHBvc2l0aW9uID0gJ2RvZGdlJyApICsKICBnZ3RpdGxlKCJNZWRpY2F0aW9uIFBheW1lbnRzIGJ5IE1vZGFsaXR5IikgKyAKICBsYWJzKHg9Ik1lZGljYXRpb25zIiwgeSA9ICdBdmVyYWdlIG9mIHBlcmNlbnRhZ2UgUGF5bWVudHMnKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSxoanVzdD0xKSkgCiAKIGdncGxvdGx5KHgpCmBgYAoKYGBge3J9CmRmICU+JSAKICBzZWxlY3QobW9kYWxpdHlfY29zdF9jb2RlLGNvc3RfY29kZSxkZXNjcmlwdGlvbixyZW1pdF90b3RhbF9jaGFyZ2VkLHJlbWl0X3RvdGFsX3BhaWQpICU+JSAKICAgIGZpbHRlcihjb3N0X2NvZGU+MzAwMCAmIGNvc3RfY29kZTw1MDAwKSAlPiUgIAogICAgbXV0YXRlKCdwZXJjZW50YWdlX3BhaWQnID0gcm91bmQocmVtaXRfdG90YWxfcGFpZC9yZW1pdF90b3RhbF9jaGFyZ2VkICogMTAwLDIpKSAlPiUgCiAgICBncm91cF9ieShtb2RhbGl0eV9jb3N0X2NvZGUsY29zdF9jb2RlLGRlc2NyaXB0aW9uKSAlPiUgCiAgc3VtbWFyaXplKCdhdmdfcGVyX3BhaWQnPW1lYW4ocGVyY2VudGFnZV9wYWlkKSkgJT4lIAogIGFycmFuZ2UoY29zdF9jb2RlLG1vZGFsaXR5X2Nvc3RfY29kZSkgCmBgYApMaXN0IG9mIEhDUEMgY29kZXMgZm9yIGRydWdzCmBgYHtyfQpkaXN0aW5jdChkZixjb3N0X2NvZGUsZGVzY3JpcHRpb24sbW9kYWxpdHlfY29zdF9jb2RlcykgCgogCgpgYGAKCgpBTkFMWVNJUyBPTiBUUkVBVE1FTlRTCmBgYHtyfQojI29ubHkgdHJlYXRtZW50cwp0cmVhdG1lbnRzPC1kZiAlPiUgCiAgICAgICAgICAgIGdyb3VwX2J5KGNvc3RfY29kZSkgJT4lIAogICAgICAgICAgICBmaWx0ZXIoY29zdF9jb2RlPDE1MTApIAoKdHJlYXRtZW50X3N1bW1hcmllczwtdHJlYXRtZW50cyAlPiUgCiAgbXV0YXRlKCd0cmVhdG1lbnRfdHlwZScgPSBjYXNlX3doZW4obW9kYWxpdHlfY29zdF9jb2RlICVpbiUgYygnMTExMCcsJzEyMTAnLCcxMzEwJykgfiAiMTExMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gbW9kYWxpdHlfY29zdF9jb2RlKSkgJT4lIAogIGdyb3VwX2J5KHRyZWF0bWVudF90eXBlLGRlc2NyaXB0aW9uKSAlPiUgCiAgc3VtbWFyaXNlKCd0b3RhbF9jaGFyZ2VzJz1zdW0ocmVtaXRfdG90YWxfY2hhcmdlZCksJ3RvdGFsX3BhaWQnID0gc3VtKHJlbWl0X3RvdGFsX3BhaWQpKSAlPiUgCiAgbXV0YXRlKCdwZXJjZW50YWdlX3BhaWQnID0gcm91bmQodG90YWxfcGFpZC90b3RhbF9jaGFyZ2VzICogMTAwLDIpKSAlPiUgCiAgYXJyYW5nZShkZXNjKHBlcmNlbnRhZ2VfcGFpZCkpCgp0cmVhdG1lbnRfc3VtbWFyaWVzCiAgCmBgYAoKIApgYGB7cn0KdHJlYXRtZW50X3N1bW1hcmllcyAlPiUgCmdncGxvdChhZXMocmVvcmRlcih4PWRlc2NyaXB0aW9uLHRvdGFsX3BhaWQpLHk9dG90YWxfcGFpZCxmaWxsID0gZGVzY3JpcHRpb24pKSsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpKwogIGNvb3JkX2ZsaXAoKSsKICB0aGVtZV9idygpKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSxoanVzdD0xKSkrCiAgIyBnZW9tX3RleHQoYWVzKGxhYmVsPXRvdGFsX3BhaWQpLCB2anVzdD0wKSArIAogIHhsYWIoIlRyZWF0bWVudCBUeXBlcyIpICsKICB5bGFiKCJOdW1iZXIgb2YgVHJlYXRtZW50cyIpICsKICBnZ3RpdGxlKCJQYXltZW50cyBieSBUcmVhdG1lbnRzIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKICAKYGBgCmBgYHtyfQp0cmVhdG1lbnRfc3VtbWFyaWVzICU+JSAKZ2dwbG90KGFlcyhyZW9yZGVyKHg9ZGVzY3JpcHRpb24scGVyY2VudGFnZV9wYWlkKSx5PXBlcmNlbnRhZ2VfcGFpZCxmaWxsID0gZGVzY3JpcHRpb24pKSsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpKwogIGdlb21fdGV4dChhZXMobGFiZWw9cGVyY2VudGFnZV9wYWlkKSwgdmp1c3Q9MCkgKyAKICAjY29vcmRfZmxpcCgpKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSxoanVzdD0xKSkrCiAgeGxhYigiVHJlYXRtZW50cyIpICsKICB5bGFiKCJQZXJjZW50YWdlIG9mIENoYXJnZXMgcGFpZCBiYWNrIikgKwogIGdndGl0bGUoIkZvciB3aGljaCBUcmVhdG1lbnRzIEdvb2QgUGVyY2VudGFnZSBvZiBDaGFyZ2UgaXMgUGFpZCBCYWNrIikrCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYApgYGB7cn0KCgpnZ2RvdGNoYXJ0KHRyZWF0bWVudF9zdW1tYXJpZXMsIHggPSAiZGVzY3JpcHRpb24iLCB5ID0gInBlcmNlbnRhZ2VfcGFpZCIsCiAgICAgICAgICAgY29sb3IgPSAiZGVzY3JpcHRpb24iLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBDb2xvciBieSBncm91cHMKICAgICAgICAgICBwYWxldHRlID0gYygiIzk5OTk5OSIsICIjRTY5RjAwIiwgIiM1NkI0RTkiLCAiIzAwOUU3MyIsIiNGMEU0NDIiLCAiIzAwNzJCMiIsICIjRDU1RTAwIiwgIiNDQzc5QTciKSwKICAgICAgICAgICAjIEN1c3RvbSBjb2xvciBwYWxldHRlCiAgICAgICAgICAgc29ydGluZyA9ICJhc2NlbmRpbmciLCAgICAgICAgICAgICAgICAgICAgICAgICMgU29ydCB2YWx1ZSBpbiBkZXNjZW5kaW5nIG9yZGVyCiAgICAgICAgICAgYWRkID0gInNlZ21lbnRzIiwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgQWRkIHNlZ21lbnRzIGZyb20geSA9IDAgdG8gZG90cwogICAgICAgICAgIGdndGhlbWUgPSB0aGVtZV9wdWJyKCksCiAgICAgICAgICAgc2l6ZSA9IDgKICAgICAgICAgICApICsKICAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1wZXJjZW50YWdlX3BhaWQpLCB2anVzdD0wLHNpemU9MykgKyAKdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzYwLGhqdXN0PTEpKSsKICBjb29yZF9mbGlwKCkgKwogIGxhYnModGl0bGUgPSAiUGVyY2VudGFnZSBQYWlkIEJhY2sgYnkgVHJlYXRtZW50IFR5cGVzIix4PSJUcmVhdG1lbnQgVHlwZXMiLCB5ID0gIlBlcmNlbnRhZ2UgJSIpCmBgYAogClBBWU1FTlRTIFNUUlVDVFVSRSBPRiBQQVlPUlMKIApgYGB7cn0KZGYgJT4lIAogIGdyb3VwX2J5KHBjbl9wYXllcl9jb2RlKSAlPiUgCiBzdW1tYXJpc2UoJ3RvdGFsX2NoYXJnZXMnPXN1bShyZW1pdF90b3RhbF9jaGFyZ2VkKSwndG90YWxfcGFpZCcgPSBzdW0ocmVtaXRfdG90YWxfcGFpZCkpICU+JSAKICBtdXRhdGUoJ3BlcmNlbnRhZ2Vfb2ZfcGF5bWVudHMnID0gcm91bmQodG90YWxfcGFpZC90b3RhbF9jaGFyZ2VzKjEwMCwyKSkgJT4lIAogICAgbXV0YXRlKCdwZXJfcGF5bWVudF9vdmVyYWxsJyA9IHJvdW5kKCh0b3RhbF9wYWlkL3N1bSh0b3RhbF9wYWlkKSkqMTAwLDIpKQpgYGAKCmBgYHtyfQpkZiAlPiUgCiAgZ3JvdXBfYnkocGNuX3BheWVyX2NvZGUpICU+JSAKICAgIGZpbHRlciAocGNuX3BheWVyX2NvZGUgIT0nMDIzNzEwMDEnKSAlPiUgCiBzdW1tYXJpc2UoJ3RvdGFsX2NoYXJnZXMnPXN1bShyZW1pdF90b3RhbF9jaGFyZ2VkKSwndG90YWxfcGFpZCcgPSBzdW0ocmVtaXRfdG90YWxfcGFpZCkpICU+JSAKICBtdXRhdGUoJ3BlcmNlbnRhZ2Vfb2ZfcGF5bWVudHMnID0gcm91bmQodG90YWxfcGFpZC90b3RhbF9jaGFyZ2VzKjEwMCwyKSkgJT4lIAogICAgbXV0YXRlKCdwZXJfcGF5bWVudF9vdmVyYWxsJyA9IHJvdW5kKCh0b3RhbF9wYWlkL3N1bSh0b3RhbF9wYWlkKSkqMTAwLDIpKSAlPiUgCmFycmFuZ2UoZGVzYyhwZXJfcGF5bWVudF9vdmVyYWxsKSkgICU+JSAKICBnZ3Bsb3QoYWVzKHJlb3JkZXIoeD1wY25fcGF5ZXJfY29kZSxwZXJfcGF5bWVudF9vdmVyYWxsKSx5PXBlcl9wYXltZW50X292ZXJhbGwsZmlsbCA9IHJlb3JkZXIoeD1wY25fcGF5ZXJfY29kZSxwZXJfcGF5bWVudF9vdmVyYWxsKSkpICsKICBnZW9tX2NvbChzdGF0PSJpZGVudGl0eSIpICsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsaGp1c3Q9MSkpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikrCiAgICBnZ3RpdGxlKCJPdGhlciBQYXlvcnMgcGF5bWVudCBwZXJjZW50YWdlIikrCiAgICBsYWJzKHg9ICJQYXlvcnMiLHk9IlBlcmNlbnRhZ2Ugb2YgUGF5bWVudHMiKQogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSsKICAgICAgdGhlbWVfbWluaW1hbCgpCiAgCiAgCmBgYAogCmBgYHtyfQpicDwtZGYgJT4lIAogIGdyb3VwX2J5KHBjbl9wYXllcl9jb2RlKSAlPiUgCiAgZmlsdGVyIChwY25fcGF5ZXJfY29kZSAhPScwMjM3MTAwMScpICU+JSAKIHN1bW1hcmlzZSgndG90YWxfY2hhcmdlcyc9c3VtKHJlbWl0X3RvdGFsX2NoYXJnZWQpLCd0b3RhbF9wYWlkJyA9IHN1bShyZW1pdF90b3RhbF9wYWlkKSkgJT4lIAogIG11dGF0ZSgncGVyY2VudGFnZV9vZl9wYXltZW50cycgPSByb3VuZCh0b3RhbF9wYWlkL3RvdGFsX2NoYXJnZXMqMTAwLDIpKSAlPiUgCiAgICBtdXRhdGUoJ3Blcl9wYXltZW50X292ZXJhbGwnID0gcm91bmQoKHRvdGFsX3BhaWQvc3VtKHRvdGFsX3BhaWQpKSoxMDAsMikpICU+JSAKICBnZ3Bsb3QoYWVzKHg9IiIseT1wZXJjZW50YWdlX29mX3BheW1lbnRzLGZpbGwgPSBwY25fcGF5ZXJfY29kZSkpKwogIGdlb21fYmFyKHdpZHRoID0gMSwgc3RhdCA9ICJpZGVudGl0eSIpCgogcGllX2NoYXJ0IDwtIGJwICsgY29vcmRfcG9sYXIoInkiLHN0YXJ0ID0gMCkgKwogICBsYWJzKHRpdGxlID0gIlBheW1lbnQgcGVyY2VudGFnZSBieSBwYXlvciIpICsKICAgdGhlbWVfdm9pZCgpICAKcGllX2NoYXJ0CiAKIApgYGAKYGBge3J9CnRlc3QgPC0gY29tcGFyZV9hY3R1YWxzX3RvX3ByZWQgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgZmlsdGVyKCEhYXMuc3ltYm9sKGlucHV0JGFsZ29fcGF5b3JzKSA9PSAxICkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgZmlsdGVyKCEhYXMuc3ltYm9sKGlucHV0JGFsZ29fbW9kYWxpdHkpID09IDEpJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihwY25fcGF5ZXJfY29kZV8wMjM3MTAwMSA9PSAxICYgaGNwY19jb2RlXzkwOTk5PT0xICkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChhY3R1YWwscHJlZGljdGVkLHBlcmNlbnRhZ2VfZGlmZmVyZW5jZSApICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZSgnQWN0dWFsJyA9IG1lYW4oYWN0dWFsKSwnUHJlZGljdGVkJyA9IG1lYW4ocHJlZGljdGVkKSkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBpdm90X2xvbmdlcihBY3R1YWw6UHJlZGljdGVkLG5hbWVzX3RvID0gIlByZWRpY3Rpb25zIiwgdmFsdWVzX3RvID0gInBlcmNlbnRhZ2VfcHJlZGljdGVkIikKCmdldF9wZXJjZW50YWdlX3ZhbHVlPC10ZXN0ICAlPiUgCiAgZmlsdGVyKFByZWRpY3Rpb25zID09ICJQcmVkaWN0ZWQiKSAlPiUgCiAgc2VsZWN0KHBlcmNlbnRhZ2VfcHJlZGljdGVkKQoKIApnZXRfcGVyY2VudGFnZV92YWx1ZSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIApgYGAKCiAKCmBgYHtyfQpQYXlvcnNfYmFyX3BsdDwtZGYgJT4lIAogICAgICAgICAgICAgICAgICBncm91cF9ieShwY25fcGF5ZXJfY29kZSkgJT4lIAogICAgICAgICAgICAgICAgICBzdW1tYXJpc2UoJ3RvdGFsX2NoYXJnZXMnPXN1bShyZW1pdF90b3RhbF9jaGFyZ2VkKSwndG90YWxfcGFpZCcgPSBzdW0ocmVtaXRfdG90YWxfcGFpZCkpICU+JSAKICAgICAgICAgICAgICAgICAgbXV0YXRlKCdwZXJjZW50YWdlX29mX3BheW1lbnRzJyA9IHJvdW5kKHRvdGFsX3BhaWQvc3VtKHRvdGFsX3BhaWQpKjEwMCwyKSkgJT4lIAogICAgICAgICAgICAgICAgICBnZ3Bsb3QoYWVzKHJlb3JkZXIoeD1wY25fcGF5ZXJfY29kZSxwZXJjZW50YWdlX29mX3BheW1lbnRzKSx5PXBlcmNlbnRhZ2Vfb2ZfcGF5bWVudHMsZmlsbCA9IHBjbl9wYXllcl9jb2RlLHRleHQ9cGVyY2VudGFnZV9vZl9wYXltZW50cykpKwogICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLGhqdXN0PTEpKSArCiAgICAgICAgICAgICAgICAgIGdlb21fYmFyKCAgc3RhdCA9ICJpZGVudGl0eSIpKwogICAgICAgICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICAgICAgICAgICAgICAgICAgbGFicyh4PSJQYXlvcnMiLHk9IlBlcmNlbnRhZ2Ugb2YgVG90YWwgIFBheW1lbnRzIixUaXRsZSA9ICJQZXJjZW50YWdlIG9mIFRvdGFsIFBheW1lbnRzIEZvciBFYWNoIFBheW9yICIpCgpnZ3Bsb3RseShQYXlvcnNfYmFyX3BsdCx0b29sdGlwID0gInRleHQiKQpgYGAKCgpQRVJDRU5UQUdFIE9GIFBBWU1FTlRTIEJZIFBBWU9SCmBgYHtyfQpicDwtZGYgJT4lIAogIGdyb3VwX2J5KHBjbl9wYXllcl9jb2RlKSAlPiUgCiBzdW1tYXJpc2UoJ3RvdGFsX2NoYXJnZXMnPXN1bShyZW1pdF90b3RhbF9jaGFyZ2VkKSwndG90YWxfcGFpZCcgPSBzdW0ocmVtaXRfdG90YWxfcGFpZCkpICU+JSAKICBtdXRhdGUoJ3BlcmNlbnRhZ2Vfb2ZfcGF5bWVudHMnID0gcm91bmQodG90YWxfcGFpZC9zdW0odG90YWxfcGFpZCkqMTAwLDIpKSAlPiUgCiAgZ2dwbG90KGFlcyh4PSIiLHk9cGVyY2VudGFnZV9vZl9wYXltZW50cyxmaWxsID0gcGNuX3BheWVyX2NvZGUpKSsKICBnZW9tX2Jhcih3aWR0aCA9IDEsIHN0YXQgPSAiaWRlbnRpdHkiKQpicAoKIHBpZV9jaGFydCA8LSBicCArIGNvb3JkX3BvbGFyKCJ5IixzdGFydCA9IDApICsKICAgbGFicyh0aXRsZSA9ICJNYWpvcml0eSBvZiBQYXltZW50cyBjb21pbmcgZnJvbSBQYXlvcjogMDIzNzEwMTAiKSArCiAgIHRoZW1lX3ZvaWQoKSAgCgpwaWVfY2hhcnQKIzkyLjU4CiAKYGBgClRBS0UgT1VUIFRIRSBNQUpPUiBQQVlPUiBBTkQgU0VFIEhPVyBPVEhFUlMgQVJFIERPSU5HCmBgYHtyfQoKYnA8LWRmICU+JSAKICBncm91cF9ieShwY25fcGF5ZXJfY29kZSkgJT4lIAogc3VtbWFyaXNlKCd0b3RhbF9jaGFyZ2VzJz1zdW0ocmVtaXRfdG90YWxfY2hhcmdlZCksJ3RvdGFsX3BhaWQnID0gc3VtKHJlbWl0X3RvdGFsX3BhaWQpKSAlPiUgCiAgbXV0YXRlKCdwZXJjZW50YWdlX29mX3BheW1lbnRzJyA9IHJvdW5kKHRvdGFsX3BhaWQvc3VtKHRvdGFsX3BhaWQpKjEwMCwyKSkgJT4lIAogICAgbXV0YXRlKCdwZXJfcGF5bWVudF9vdmVyYWxsJyA9IHJvdW5kKCh0b3RhbF9wYWlkL3N1bSh0b3RhbF9wYWlkKSkqMTAwLDIpKSAlPiUgCiAgZmlsdGVyKHBjbl9wYXllcl9jb2RlICE9JzAyMzcxMDAxJykgJT4lIAogIGdncGxvdChhZXMoeD0iIix5PXBlcmNlbnRhZ2Vfb2ZfcGF5bWVudHMsZmlsbCA9IHBjbl9wYXllcl9jb2RlKSkrCiAgZ2VvbV9iYXIod2lkdGggPSAxLCBzdGF0ID0gImlkZW50aXR5IikKYnAKCiBwaWVfY2hhcnQgPC0gYnAgKyBjb29yZF9wb2xhcigieSIsc3RhcnQgPSAwKSArCiAgIGxhYnModGl0bGUgPSAiUGF5bWVudHMgQnkgT3RoZXIgUGF5b3JzIikgKwogICB0aGVtZV92b2lkKCkgCiAKICAgZ2VvbV90ZXh0KGFlcyh5ID0gdmFsdWUvMyArIGMoMCwgY3Vtc3VtKHZhbHVlKVstbGVuZ3RoKHZhbHVlKV0pLCAKICAgICAgICAgICAgbGFiZWwgPSBwZXJjZW50KHZhbHVlLzEwMCkpLCBzaXplPTUpCgpwaWVfY2hhcnQKYGBgCgogCiAKIApgYGB7cn0KZ2dwbG90KGRmKSArIApnZW9tX2JhcihhZXMoeD1wY25fcGF5ZXJfY29kZSwgeT1yZW1pdF90b3RhbF9wYWlkLCBjb2xvcj1wY25fcGF5ZXJfY29kZSksc3RhdD0iaWRlbnRpdHkiKSArIGdlb21fc21vb3RoKGFlcyh4PXBjbl9wYXllcl9jb2RlLCB5PXJlbWl0X3RvdGFsX3BhaWQpKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLGhqdXN0PTEpKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAogCgpgYGB7cn0KZGYgJT4lIAogIGZpbHRlcihwY25fcGF5ZXJfY29kZSE9JzAyMzcxMDAxJykgJT4lIAogIHNlbGVjdCAocGNuX3BheWVyX2NvZGUsbW9kYWxpdHlfY29zdF9jb2RlLHJlbWl0X3RvdGFsX3BhaWQpICU+JSAKICBncm91cF9ieShtb2RhbGl0eV9jb3N0X2NvZGUscGNuX3BheWVyX2NvZGUpICU+JSAKICBzdW1tYXJpc2UoJ2F2Z19wYWlkJyA9IG1lYW4ocmVtaXRfdG90YWxfcGFpZCkpICU+JSAKICBnZ3Bsb3QoKSArIGdlb21fY29sKGFlcyh4PXBjbl9wYXllcl9jb2RlLCB5PWF2Z19wYWlkLGZpbGwgPSBwY25fcGF5ZXJfY29kZSkpKwogICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLGhqdXN0PTIpKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKIApQQVlNRU5UUyBCWSBUUkVBVE1FTlRTCmBgYHtyfQp0czwtdHJlYXRtZW50X3N1bW1hcmllcyAlPiUgCiBnZ3Bsb3QoYWVzKHg9cmVvcmRlcihkZXNjcmlwdGlvbixwZXJjZW50YWdlX3BhaWQpLHk9cGVyY2VudGFnZV9wYWlkLGZpbGwgPSBkZXNjcmlwdGlvbikpKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsaGp1c3Q9MSkpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKdHMKCiAKYGBgClBBWU1FTlRTIEJZIE5PTi1UUkVBVE1FTlQgU0VSVklDRVMgQ09TVCBDT0RFUyBsaWtlIG1lZHMgc3VwcGxpZXMgZXRjCmBgYHtyfQoKZGYgJT4lIAogIGZpbHRlcihjb3N0X2NvZGUgPicxNTEwJykgJT4lIAogIGdyb3VwX2J5KGNvc3RfY29kZSApICU+JSAKc3VtbWFyaXNlKCd0b3RhbF9jaGFyZ2VzJz1zdW0ocmVtaXRfdG90YWxfY2hhcmdlZCksJ3RvdGFsX3BhaWQnID0gc3VtKHJlbWl0X3RvdGFsX3BhaWQpKSAlPiUgCiAgbXV0YXRlKCdwZXJjZW50YWdlX3BhaWQnID0gdG90YWxfcGFpZC90b3RhbF9jaGFyZ2VzICogMTAwKSAlPiUgCiAgZmlsdGVyKHBlcmNlbnRhZ2VfcGFpZD4wKSAlPiUgCiAgbXV0YXRlKCdwZXJfcGF5bWVudF9vdmVyYWxsJyA9IHJvdW5kKCh0b3RhbF9wYWlkL3N1bSh0b3RhbF9wYWlkKSkqMTAwLDIpKSAlPiUgCiAgYXJyYW5nZShkZXNjKHBlcl9wYXltZW50X292ZXJhbGwpKSAlPiUgCiAgZ2dwbG90KGFlcyh4PSBmYWN0b3IoY29zdF9jb2RlKSx5PXBlcl9wYXltZW50X292ZXJhbGwsZmlsbCA9IGZhY3Rvcihjb3N0X2NvZGUpKSkgKwogIGdlb21fY29sKHN0YXRfY291bnQgPSAiaWRlbnRpdHkiKSsKICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCxoanVzdD0yKSkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKYGBge3J9CiAKICBkaXN0aW5jdChkZixjb3N0X2NvZGUsZGVzY3JpcHRpb24pJT4lIAogIGZpbHRlcihjb3N0X2NvZGUgJWluJSBjKCczNjA1JywnMzYyMScsJzcwNjAnLCczNjEzJykpCmBgYAogCgoKYGBge3J9CmRmICU+JSAKICBzZWxlY3QoZGF0ZV9vZl9zZXJ2aWNlLHBhdGllbnRfaWQsY29zdF9jb2RlLHJlbWl0X3RvdGFsX3BhaWQscGNuX3BheWVyX2NvZGUpICU+JSAKICBnZ3Bsb3QoYWVzKHg9YXMuZmFjdG9yKGNvc3RfY29kZSkseT1yZW1pdF90b3RhbF9wYWlkKSkgK2dlb21fcG9pbnQoKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLGhqdXN0PTEpKSArCiAgbGFicyh4PSJDb3N0IENvZGVzIix5PSJUb3RhbCBwYXltZW50cyIsdGl0bGUgPSAiVG90YWwgUGF5bWVudHMgYnkgQ29zdCBDb2RlcyIpCmBgYApJUyBUSEVSRSBBTlkgUkVMQVRJT04gQkVUV0VFTiBQQVlNRU5UIEFORCBIQ1RfUEVSPyBOTwpgYGB7cn0KcGwgPC0gZ2dwbG90KGRmLCBhZXMoeD1oY3RfcGVyLHk9cmVtaXRfdG90YWxfcGFpZCkgKSArCiAgZ2VvbV9wb2ludChhbHBoYT0wLjIpICsgZ2VvbV9zbW9vdGgobWV0aG9kID0gJ2xtJykgKwogIHNjYWxlX3hfbG9nMTAoKSArCiAgc2NhbGVfeV9sb2cxMCgpKwogIGxhYnMoeD0iSENUIHZhbHVlcyIseT0iVG90YWwgY2hhcmdlcyIsdGl0bGUgPSAiQ29ycmVsYXRpb24gYmV0d2VlbiBjaGFyZ2VzIGFuZCBIQ1QgdmFsdWVzIikKCnBsCiAKYGBgCmBgYHtyfQpjb2xuYW1lcyhkZikKYGBgCgoKCgpBTkFMWVNJUyBVU0lORyBNT0RJRklFUlMKCkcxIC0gTW9zdCByZWNlbnQgVVJSIG9mIGxlc3MgdGhhbiA2MCUKRzIgLSBNb3N0IHJlY2VudCBVUlIgb2YgNjAlIHRvIDY0LjklCkczIC0gTW9zdCByZWNlbnQgVVJSIG9mIDY1JSB0byA2OS45JQpHNCAtIE1vc3QgcmVjZW50IFVSUiBvZiA3MCUgdG8gNzQuOSUKRzUgLSBNb3N0IHJlY2VudCBVUlIgb2YgNzUlIG9yIGdyZWF0ZXIKRzYgLSBFU1JEIHBhdGllbnQgZm9yIHdob20gbGVzcyB0aGFuIHNldmVuIGRpYWx5c2lzIHNlc3Npb25zIGhhdmUgYmVlbiBwcm92aWRlZCBpbiBhIG1vbnRoLgpgYGB7cn0KCiNQRVJDRU5UQUdFIFBBSUQgQlkgcGNuJ3Mgd2l0aG91dCBtb2RpZmllcnMKCm5vX21vZGlmaWVyczwtZGYgJT4lIGZpbHRlcihpcy5uYShtb2RpZmllcl8xKSAgJiBpcy5uYShtb2RpZmllcl8yKSAmIGlzLm5hKG1vZGlmaWVyXzMpKQogCgpub19tb2RpZmllcnM8LW5vX21vZGlmaWVycyAlPiUgCiAgZ3JvdXBfYnkocGNuX3BheWVyX2NvZGUpICU+JSAKICBzdW1tYXJpc2UoJ3RvdGFsX2NoYXJnZXMnID0gc3VtKHJlbWl0X3RvdGFsX2NoYXJnZWQpLCd0b3RhbF9wYXltZW50Jz1zdW0ocmVtaXRfdG90YWxfcGFpZCkpICU+JSAKbXV0YXRlICgncGN0X3BhaWRfd2l0aF9ub19tb2RpZmllcnMnPXRvdGFsX3BheW1lbnQvdG90YWxfY2hhcmdlcyoxMDApCiAKIAp3aXRoX21vZGlmaWVyczwtZGYgJT4lIGZpbHRlcighaXMubmEobW9kaWZpZXJfMSApIHwgIWlzLm5hKCBtb2RpZmllcl8yKSAgIHwgIWlzLm5hKCBtb2RpZmllcl8zKSApCiNwZXJjZW50YWdlIHBhaWQgYnkgcGNuJ3Mgd2l0aCBtb2RpZmllcnMKd2l0aF9tb2RpZmllcnM8LXdpdGhfbW9kaWZpZXJzICU+JSAKICBncm91cF9ieShwY25fcGF5ZXJfY29kZSkgJT4lIAogIHN1bW1hcmlzZSgndGMnID0gc3VtKHJlbWl0X3RvdGFsX2NoYXJnZWQpLCd0cCc9c3VtKHJlbWl0X3RvdGFsX3BhaWQpKSAlPiUgCm11dGF0ZSAoJ3BjdF9wYWlkX3dpdGhfbW9kaWZpZXJzJz10cC90YyoxMDApCiAKIAojbWVyZ2UgIAptb2RpZmllcnM8LSBtZXJnZSh3aXRoX21vZGlmaWVycyxub19tb2RpZmllcnMsYnkgPSAicGNuX3BheWVyX2NvZGUiKSAlPiUgCiAgc2VsZWN0KHBjbl9wYXllcl9jb2RlLHBjdF9wYWlkX3dpdGhfbW9kaWZpZXJzLHBjdF9wYWlkX3dpdGhfbm9fbW9kaWZpZXJzKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKAogICAgcGN0X3BhaWRfd2l0aF9tb2RpZmllcnM6cGN0X3BhaWRfd2l0aF9ub19tb2RpZmllcnMsCiAgICBuYW1lc190byA9ICJ3aXRoX29yX3dpdGhvdXRfbW9kaWZpZXJzIiwKICAgIHZhbHVlc190byA9ICJwZXJjZW50YWdlX3BhaWQiKQogIAogbW9kaWZpZXJzX3BsdDwtZ2dwbG90KG1vZGlmaWVycyxhZXMoeSA9IHBlcmNlbnRhZ2VfcGFpZCwgeCA9IHBjbl9wYXllcl9jb2RlLGZpbGwgPSB3aXRoX29yX3dpdGhvdXRfbW9kaWZpZXJzKSkgKwogIGdlb21fYmFyKHN0YXQ9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gJ2RvZGdlJykgKwogIGxhYnMoeD0iUGF5b3JzIiwgeSA9ICJQYXltZW50cyAlIikgKwogIGdndGl0bGUoIkRpZmZlcmVuY2UgaW4gUGF5bWVudHMgV2l0aCBhbmQgV2l0aG91dCBNb2RpZmllcnMiKSsKICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwyMCwxKSkKICAKICAKIGdncGxvdGx5KG1vZGlmaWVyc19wbHQpCgpgYGAKCkRJQUdOT1NJUyBDT0RFIEFOQUxZU0lTCiAKYGBge3J9CmRwbHlyOjpjb3VudChkZixkaWFnbm9zaXNfY29kZSxzb3J0ID0gVFJVRSkKYGBgCgpOMjUuODEgLSBTZWNvbmRhcnkgaHlwZXJwYXJhdGh5cm9pZGlzbSBvZiByZW5hbCBvcmlnaW4KWjIzIGlzIGEgYmlsbGFibGUgSUNEIGNvZGUgdXNlZCB0byBzcGVjaWZ5IGEgZGlhZ25vc2lzIG9mIGVuY291bnRlciBmb3IgaW1tdW5pemF0aW9uLgoKYGBge3J9CmRpYWdub3NpczwtZGYgJT4lIGdyb3VwX2J5KGRpYWdub3Npc19jb2RlKSAlPiUgc3VtbWFyaXNlKG49bigpLHRvdGFsX2NoYXJnZWQgPSBzdW0ocmVtaXRfdG90YWxfY2hhcmdlZCksIHRvdGFsX3BhaWQgPSBzdW0ocmVtaXRfdG90YWxfcGFpZCkpICU+JSBhcnJhbmdlKGRlc2MobikpCgpkaWFnbm9zaXMKCmBgYAogCmBgYHtyfQoKZGlhZ25vc2lzICU+JSAKICBmaWx0ZXIoIWlzLm5hKGRpYWdub3Npc19jb2RlKSkgJT4lIAogIGdncGxvdChhZXMoeD1kaWFnbm9zaXNfY29kZSx5PW4sZmlsbD1kaWFnbm9zaXNfY29kZSkpICsKICBnZW9tX2NvbCgpICsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsaGp1c3Q9MSkpIApgYGAKCiAKYGBge3J9CmNvcnJzCmBgYApgYGB7cn0KIGhlYWQoYWxnb19kZl9maW5hbCkKYGBgCgoKQkVHSU4gTUFLSU5HIFBFUkNFTlRBR0UgT0YgUEFZTUVOVFMgUFJFRElDVElPTiBVU0lORyBSRUdSRVNTSU9OIEFMR09SSVRITVMuCgoxLiBPUkRJTkFSWSBMRUFTVCBTUVVBUkVTIE1PREVMCmBgYHtyfQojRmlyc3QsIHNwbGl0IHRoZSBkYXRhIGluIGFsZ29fZGZfZmluYWwgZGF0YXNldCB3aXRoIDc1IHBlcmNlbnRpbGUKc2V0LnNlZWQoMjM3KQppbmRleCA9IGNyZWF0ZURhdGFQYXJ0aXRpb24oYWxnb19kZl9maW5hbCRoY3RfcGVyLHA9MC43NSxsaXN0ID0gRkFMU0UpCgojc2F2ZSB0aGUgNzUlIG9mIGRhdGEgaW4gdHJhaW5TZXQgYW5kIDI1JSBpbiB0ZXN0IHNldC4KdHJhaW5TZXQgPC0gYWxnb19kZl9maW5hbFtpbmRleCxdCnRlc3RTZXQgPC0gYWxnb19kZl9maW5hbFstaW5kZXgsXQpgYGAKYGBge3J9CiNPTFMKI3RyYWluIHRoZSBtb2RlbCAKI29sc19kcyA8LSB0cmFpbihwZXJjZW50YWdlX3BheW1lbnR+LixkYXRhID0gdHJhaW5TZXQsbWV0aG9kID0gImxtIiwgbWV0cmljID0iUk1TRSIsIAogIyAgICAgICAgICAgICAgdHJDb250cm9sID0gdHJhaW5Db250cm9sKG1ldGhvZCA9ICJub25lIikpCgpvbHNfZHMgPC0gdHJhaW4ocGVyY2VudGFnZV9wYXltZW50fi4sZGF0YSA9IHRyYWluU2V0LG1ldGhvZCA9ICJsbSIpCgojdHJhaW5pbmcgc2V0IHBlcmZvcm1hbmNlCnRyYWluX3ByZWQgPC0gcHJlZGljdChvbHNfZHMsIG5ld2RhdGEgPSB0cmFpblNldCkKTUFFKHByZWQgPSB0cmFpbl9wcmVkICwgb2JzID0gdHJhaW5TZXQkcGVyY2VudGFnZV9wYXltZW50KSMxLjU1NTQzNQoKYGBgCmBgYHtyfQpwcmludChvbHNfZHMpCmBgYAoKCmBgYHtyfQojdGVzdCBzZXQKdGVzdF9wcmVkIDwtIHByZWRpY3QgKG9sc19kcywgbmV3ZGF0YSA9IHRlc3RTZXQpCk1BRShwcmVkID0gdGVzdF9wcmVkLCBvYnMgPSB0ZXN0U2V0JHBlcmNlbnRhZ2VfcGF5bWVudCkgCmBgYApgYGB7cn0KcHJpbnQodGVzdF9wcmVkKQpgYGAKCmBgYHtyfQojcHV0IHByZWRpY3Rpb25zIGluIGRhdGFmcmFtZQp0ZXN0X3ByZWQuZGY8LSBhcy5kYXRhLmZyYW1lKGFzLnZlY3Rvcih0ZXN0X3ByZWQpKQpgYGAKYGBge3J9Cm9sc19kcwpgYGAKIAoKVGhlIHRha2UgaG9tZSBtZXNzYWdlIGZyb20gdGhlIG91dHB1dCBpcyB0aGF0IGZvciBldmVyeSB1bml0IGluY3JlYXNlIGluIHRoZSBzcXVhcmUgcm9vdCBvZiBlbmdpbmUgZGlzcGxhY2VtZW50IHRoZXJlIGlzIGEgLTAuMTQyNDYgZGVjcmVhc2UgaW4gdGhlIHNxdWFyZSByb290IG9mIGZ1ZWwgZWZmaWNpZW5jeSAobXBnKS4gVGhlcmVmb3JlLCBmdWVsIGVmZmljaWVuY3kgZGVjcmVhc2VzIHdpdGggaW5jcmVhc2luZyBlbmdpbmUgZGlzcGxhY2VtZW50LgoKRmVhdXR1cmUgYW5kIGNvZWZmaWNpZW50cyBhbmFseXNpcy4KYGBge3J9CmNvZWZmaWNpZW50czwtY29lZihvbHNfZHMkZmluYWxNb2RlbCkKY29lZmZpY2llbnRzX2RmIDwtIGFzLmRhdGEuZnJhbWUoY29lZmZpY2llbnRzKQoKZmVhdHVyZXM8LXJvd25hbWVzKGNvZWZmaWNpZW50c19kZiApCmNvZWZmaWNpZW50c19mZWF0dXJlcyA8LWNiaW5kKGNvZWZmaWNpZW50cyxmZWF0dXJlcykKY29lZmZpY2llbnRzX2ZlYXR1cmVzX2RmIDwtIGFzLmRhdGEuZnJhbWUoY29lZmZpY2llbnRzX2ZlYXR1cmVzKQogCmZlYXR1cmVfYW5hbHlzaXM8LWNvZWZmaWNpZW50c19mZWF0dXJlc19kZiAlPiUgCiAgc2VsZWN0KGZlYXR1cmVzLGNvZWZmaWNpZW50cykgJT4lIAogIGZpbHRlcighaXMubmEoY29lZmZpY2llbnRzKSkgJT4lIAogIGFycmFuZ2UoZGVzYyhjb2VmZmljaWVudHMpKQpgYGAKCmBgYHtyfQpmZWF0dXJlX2FuYWx5c2lzCmBgYAogCiAKCmBgYHtyfQpvbHNfZHMkcmVzdWx0cwpgYGAKCgpTZWUgdGhlIG1ldHJpY3MKYGBge3J9CmFjdHVhbCA8LSBhcy52ZWN0b3IodGVzdFNldCRwZXJjZW50YWdlX3BheW1lbnQpCmFjdHVhbCA8LSBhcy5kYXRhLmZyYW1lKHJvdW5kKGFjdHVhbCwyKSkKY29sbmFtZXMoYWN0dWFsKSA8LSBjKCJhY3R1YWwiKQogCnByZWRpY3RlZCA8LSBhcy52ZWN0b3IodGVzdF9wcmVkKQpwcmVkaWN0ZWQgPC1hcy5kYXRhLmZyYW1lKHJvdW5kKHByZWRpY3RlZCwyKSkKY29sbmFtZXMocHJlZGljdGVkKSA8LSBjKCJwcmVkaWN0ZWQiKQpgYGAKYGBge3J9CmxpYnJhcnkoTWV0cmljcykKI2FwZSBjb21wdXRlcyB0aGUgZWxlbWVudHdpc2UgYWJzb2x1dGUgcGVyY2VudCBkaWZmZXJlbmNlIGJldHdlZW4gdHdvIG51bWVyaWMgdmVjdG9ycwphYnNvbHV0ZV9wZXJjZW50YWdlX2RpZmY8LWFwZShhY3R1YWwscHJlZGljdGVkKQphYnNvbHV0ZV9wZXJjZW50YWdlX2RpZmYgPC1hcy5kYXRhLmZyYW1lKHJvdW5kKGFic29sdXRlX3BlcmNlbnRhZ2VfZGlmZiwyKSoxMDApCmNvbG5hbWVzKGFic29sdXRlX3BlcmNlbnRhZ2VfZGlmZikgPC0gYygicGVyY2VudGFnZV9kaWZmZXJlbmNlIikKYGBgCmBgYHtyfQphY3R1YWwKYGBgCgpgYGB7cn0KI0NvbXBhcmUgYWN0dWFsIHkgdmFsdWVzIHRvIHByZWRpY3RlZCB2YWx1ZXMKY29tcGFyZV9hY3R1YWxzX3RvX3ByZWQ8LWNiaW5kKGFjdHVhbCxwcmVkaWN0ZWQsYWJzb2x1dGVfcGVyY2VudGFnZV9kaWZmLHRlc3RTZXQpCmNvbXBhcmVfYWN0dWFsc190b19wcmVkICU+JSAKICBmaWx0ZXIobW9kYWxpdHlfY29zdF9jb2RlXzExMTA9PTEgJiBwY25fcGF5ZXJfY29kZV8wMjM3MTAwMT09MSkgJT4lIAogIGFycmFuZ2UoZGVzYyhwZXJjZW50YWdlX2RpZmZlcmVuY2UpKQoKc2F2ZVJEUyhjb21wYXJlX2FjdHVhbHNfdG9fcHJlZCwnRENJX0NhcHN0b25lL2RhdGEvY29tcGFyZV9hY3R1YWxzX3RvX3ByZWQucmRzJykKYGBgCgpgYGB7cn0KI2NvbXBhcmVfYWN0dWFsc190b19wcmVkIDwtIGNiaW5kKHRlc3RTZXQkcGVyY2VudGFnZV9wYXltZW50LHRlc3RfcHJlZC5kZix0ZXN0U2V0KQojY29sbmFtZXMoY29tcGFyZV9hY3R1YWxzX3RvX3ByZWQgKSA8LSBjKCJhY3R1YWxfcGVyX3ZhbHVlcyIsInByZWRpY3RlZF9wZXJfdmFsdWVzIikKYGBgCkFsbCBmZWF0dXJlcwpgYGB7cn0KYWxsX2ZlYXR1cmVzPC1hcy5kYXRhLmZyYW1lKCBjb2xuYW1lcyhjb21wYXJlX2FjdHVhbHNfdG9fcHJlZCkpCmNvbG5hbWVzKGFsbF9mZWF0dXJlcykgPSBjKCdmZWF0dXJlcycpCgphbGxfZmVhdHVyZXMgCmBgYAoKYGBge3J9CiNtb2RhbGl0eSBjb3N0IGNvZGVzCm1vZGFsaXR5X2Nvc3RfY29kZXM8LWFsbF9mZWF0dXJlcyAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoZmVhdHVyZXMgJWxpa2UlICJtb2RhbGl0eV9jb3N0X2NvZGVfIikgJT4lIAogICAgICAgICAgICAgICAgICAgICAgYXJyYW5nZShmZWF0dXJlcykKI2RpYWdub3Npc19jb2RlcwpkaWFnbm9zaXNfY29kZXM8LWFsbF9mZWF0dXJlcyAlPiUgCiAgICAgICAgICAgICAgICBmaWx0ZXIoZmVhdHVyZXMgJWxpa2UlICJkaWFnbm9zaXNfY29kZV8iKSAlPiUgCiAgICAgICAgICAgICAgICBhcnJhbmdlKGZlYXR1cmVzKQojUmV2ZW51ZSBjb2RlcwpyZXZlbnVlX2NvZGVzIDwtYWxsX2ZlYXR1cmVzICU+JSAKICAgICAgICAgICAgICAgIGZpbHRlcihmZWF0dXJlcyAlbGlrZSUgInJldmVudWVfY29kZV8iKSAlPiUgCiAgICAgICAgICAgICAgICBhcnJhbmdlKGZlYXR1cmVzKQojbW9kaWZpZXJfMQptb2RpZmllcl8xIDwtYWxsX2ZlYXR1cmVzICU+JSAKICAgICAgICAgICAgICAgIGZpbHRlcihmZWF0dXJlcyAlbGlrZSUgIm1vZGlmaWVyXzFfIikgJT4lIAogICAgICAgICAgICAgICAgYXJyYW5nZShmZWF0dXJlcykKIAojTW9kaWZpZXJfMgptb2RpZmllcl8yIDwtYWxsX2ZlYXR1cmVzICU+JSAKICAgICAgICAgICAgICAgIGZpbHRlcihmZWF0dXJlcyAlbGlrZSUgIm1vZGlmaWVyXzJfIikgJT4lIAogICAgICAgICAgICAgICAgYXJyYW5nZShmZWF0dXJlcykKIAojTW9kaWZpZXJfMwogbW9kaWZpZXJfMyA8LWFsbF9mZWF0dXJlcyAlPiUgCiAgICAgICAgICAgICAgICBmaWx0ZXIoZmVhdHVyZXMgJWxpa2UlICJtb2RpZmllcl8zXyIpICU+JSAKICAgICAgICAgICAgICAgIGFycmFuZ2UoZmVhdHVyZXMpCgojaGNwY19jb2RlCmhjcGNfY29kZSA8LWFsbF9mZWF0dXJlcyAlPiUgCiAgICAgICAgICAgICAgICBmaWx0ZXIoZmVhdHVyZXMgJWxpa2UlICJoY3BjX2NvZGVfIikgJT4lIAogICAgICAgICAgICAgICAgYXJyYW5nZShmZWF0dXJlcykKI3Bjbl9wYXlvcl9jb2RlIApwY25fcGF5b3JfY29kZSA8LWFsbF9mZWF0dXJlcyAlPiUgCiAgICAgICAgICAgICAgICBmaWx0ZXIoZmVhdHVyZXMgJWxpa2UlICJwY25fcGF5ZXJfY29kZV8iKSAlPiUgCiAgICAgICAgICAgICAgICBhcnJhbmdlKGZlYXR1cmVzKQpgYGAKYGBge3J9CmNvbXBhcmVfYWN0dWFsc190b19wcmVkICU+JSAKICBmaWx0ZXIocGNuX3BheWVyX2NvZGVfMDIzNzEwMDEgPT0gMSAmIG1vZGFsaXR5X2Nvc3RfY29kZV8xMTEwPT0xKSAlPiUgCiAgc2VsZWN0KHBjbl9wYXllcl9jb2RlXzAyMzcxMDAxLGFjdHVhbCxtb2RhbGl0eV9jb3N0X2NvZGVfMTExMCxwcmVkaWN0ZWQscGVyY2VudGFnZV9kaWZmZXJlbmNlICkgJT4lCiAgc3VtbWFyaXNlKCdhdmdfYWN0dWFsJyA9IG1lYW4oYWN0dWFsKSwnYXZnX3ByZWRpY3RlZCcgPSBtZWFuKHByZWRpY3RlZCkpICU+JSAKICBwaXZvdF9sb25nZXIoYXZnX2FjdHVhbDphdmdfcHJlZGljdGVkLG5hbWVzX3RvID0gIlByZWRpY3Rpb25fdHlwZSIsIHZhbHVlc190byA9ICJQZXJjZW50YWdlX3ZhbHVlcyIpCmBgYApgYGB7cn0KcGNuX3BheW9yX2NvZGUKYGBgCmBgYHtyfQptb2RhbGl0eV9jb3N0X2NvZGVzX3NoaW55CmBgYAoKYGBge3J9CiNjb21wYXJlX2FjdHVhbHNfdG9fcHJlZCAlPiUgCnRyYWluU2V0ICU+JSAKICBmaWx0ZXIocGNuX3BheWVyX2NvZGVfMDIzNzEwMDEgPT0gMSAmIG1vZGFsaXR5X2Nvc3RfY29kZV8xMTEwPT0xLGhjcGNfY29kZV85MDk5OT09MSAgKSAKYGBgCmBgYHtyfQp0cmFpblNldCAlPiUgCiAgZmlsdGVyKHBjbl9wYXllcl9jb2RlXzAyMzcxMDAxID09IDEgJiBtb2RhbGl0eV9jb3N0X2NvZGVfMTExMD09MSAmaGNwY19jb2RlXzkwOTk5PT0xICkKYGBgCgoKQmFyIHBsb3RzIGZvciBBY3R1YWwgdnMgUHJlZGljdGVkCmBgYHtyfQoKY29tcGFyZV9hY3R1YWxzX3RvX3ByZWRfcGx0IDwtY29tcGFyZV9hY3R1YWxzX3RvX3ByZWQgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIocGNuX3BheWVyX2NvZGVfMDIzNzEwMDEgPT0gMSAmIGhjcGNfY29kZV85MDk5OT09MSApICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KGFjdHVhbCxwcmVkaWN0ZWQscGVyY2VudGFnZV9kaWZmZXJlbmNlICkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZSgnQWN0dWFsJyA9IG1lYW4oYWN0dWFsKSwnUHJlZGljdGVkJyA9IG1lYW4ocHJlZGljdGVkKSkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwaXZvdF9sb25nZXIoQWN0dWFsOlByZWRpY3RlZCxuYW1lc190byA9ICJQcmVkaWN0aW9ucyIsIHZhbHVlc190byA9ICJwZXJjZW50YWdlX3ByZWRpY3RlZCIpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2dwbG90KGFlcyh4ID0gUHJlZGljdGlvbnMsIHkgPSBwZXJjZW50YWdlX3ByZWRpY3RlZCxmaWxsID0gUHJlZGljdGlvbnMpKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fdGV4dChhZXMobGFiZWw9cm91bmQocGVyY2VudGFnZV9wcmVkaWN0ZWQsMikpLCB2anVzdD0wLHNpemU9NSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9jb2woIGFscGhhPSAwLjcpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiZ3JleSIsImRhcmtzbGF0ZWdyZXkiKSkrCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdndGl0bGUoIkNvbXBhcmluZyBBY3R1YWwgUGF5bWVudCAlIHRvIFByZWRpY3RlZCAlIEZvciAwMjM3MTAwMSBhbmQgUE5FTU9WQVgiKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYnMoeCA9ICJBY3R1YWwgVnMgUHJlZGljdGVkIiwgeSA9ICJQZXJjZW50YWdlICUiKSsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKZ2dwbG90bHkoY29tcGFyZV9hY3R1YWxzX3RvX3ByZWRfcGx0KQogIApgYGAKCiAKYGBge3J9CmNvbXBhcmVfYWN0dWFsc190b19wcmVkICU+JSAKICBmaWx0ZXIocGNuX3BheWVyX2NvZGVfMDIzNzEwMDEgPT0gMSAgJiBoY3BjX2NvZGVfOTA5OTk9PTEgKSAlPiUgCiAgIHNlbGVjdChhY3R1YWwscHJlZGljdGVkLHBlcmNlbnRhZ2VfZGlmZmVyZW5jZSApICU+JSAKIHBpdm90X2xvbmdlcihhY3R1YWw6cHJlZGljdGVkLG5hbWVzX3RvID0gInByZWRpY3Rpb24iLCB2YWx1ZXNfdG8gPSAicGVyY2VudGFnZV9wcmVkaWN0ZWQiKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gcHJlZGljdGlvbiwgeSA9IHBlcmNlbnRhZ2VfcHJlZGljdGVkLGZpbGwgPSBwcmVkaWN0aW9uKSkgKwogIGdlb21fYm94cGxvdChhbHBoYT0wLjUgKSArCiAgZ2d0aXRsZSgiQ29tcGFyaW5nIEFjdHVhbCBQYXltZW50ICUgdG8gUHJlZGljdGVkICUiKSArCiAgbGFicyh4ID0gIkFjdHVhbCBWcyBQcmVkaWN0ZWQiLCB5ID0gIlBlcmNlbnRhZ2UiKQogIApgYGAKCiAKCgpMQVNTTyBSRUdSRVNTSU9OCmBgYHtyfQojTGFzc28Kc3VtKGlzLm5hKGFsZ29fZGZfZmluYWwpKQpgYGAKIAoKYGBge3J9CmxpYnJhcnkoZ2xtbmV0KQpzZXQuc2VlZCgyMDApCmluZGV4ID0gY3JlYXRlRGF0YVBhcnRpdGlvbihhbGdvX2RmX2ZpbmFsJHBlcmNlbnRhZ2VfcGF5bWVudCxwPTAuNzUsbGlzdD1GQUxTRSkKCnRyYWluU2V0IDwtIGFsZ29fZGZfZmluYWxbaW5kZXgsXQp0ZXN0U2V0IDwtIGFsZ29fZGZfZmluYWxbLWluZGV4LF0KIAp4X3RyYWluIDwtIHRyYWluU2V0ICU+JSBzZWxlY3QoLXBlcmNlbnRhZ2VfcGF5bWVudCkgJT4lICBhcy5tYXRyaXgoKQp4X3Rlc3QgPC0gdGVzdFNldCAlPiUgc2VsZWN0KC1wZXJjZW50YWdlX3BheW1lbnQpICU+JSBhcy5tYXRyaXgoKQoKeV90cmFpbiA8LSB0cmFpblNldCRwZXJjZW50YWdlX3BheW1lbnQKeV90ZXN0IDwtIHRlc3RTZXQkcGVyY2VudGFnZV9wYXltZW50CiAKI2xldHMgc3RhbmRhcmRpemUgdGhlIGRhdGEKcHJlUHJvY1ZhbHVlcyA8LSBwcmVQcm9jZXNzKHhfdHJhaW4sIG1ldGhvZCA9IGMoImNlbnRlciIsInNjYWxlIikpCgp4X3RyYWluVHJhbnNmb3JtZWQgPC0gcHJlZGljdChwcmVQcm9jVmFsdWVzLHhfdHJhaW4pCnhfdGVzdFRyYW5zZm9ybWVkPC0gcHJlZGljdChwcmVQcm9jVmFsdWVzLHhfdGVzdCkKCiN0cmFpbiB0aGUgbW9kZWwKbGFzc29fbW9kZWwgPC0gZ2xtbmV0KHhfdHJhaW5UcmFuc2Zvcm1lZCx5X3RyYWluLGFscGhhID0gMSxsYW1iZGEgPSBOVUxMKQoKdHJhaW5fcHJlZDwtIHByZWRpY3QobGFzc29fbW9kZWwsbmV3eD14X3RyYWluVHJhbnNmb3JtZWQpCk1BRShwcmVkID0gdHJhaW5fcHJlZCwgb2JzID0geV90cmFpbikgCmBgYApgYGB7cn0KdGVzdF9wcmVkPC0gcHJlZGljdChsYXNzb19tb2RlbCxuZXd4PXhfdGVzdFRyYW5zZm9ybWVkKQpNQUUocHJlZD10ZXN0X3ByZWQsb2JzPXlfdGVzdCkjIDIuMDkxOTMyCgojdXNlIGNyb3NzZm9sZApjdiA8LSBjdi5nbG1uZXQoeF90cmFpblRyYW5zZm9ybWVkLHlfdHJhaW4sIGFscGhhPTEpI2FscGhhID0gMSBtZWFucyBsYXNzbyBhbmQgMCBtZWFucyByaWRnZQogCmN2JGxhbWJkYS5taW4KCiNyZXRyYWluIHRoZSBtb2RlbCB3aXRoIG1pbmltdW0gbGFtZGJhIHZhbHVlCmZpdD1nbG1uZXQoeF90cmFpblRyYW5zZm9ybWVkLHlfdHJhaW4sIGFscGhhID0gMSwgbGFtYmRhID0gY3YkbGFtYmRhLm1pbikKCnRlc3RfcHJlZGljdGlvbnNfcmVmaXR0ZWQ8LSBwcmVkaWN0KGZpdCxuZXd4PXhfdGVzdFRyYW5zZm9ybWVkKQoKTUFFKHByZWQ9dGVzdF9wcmVkaWN0aW9uc19yZWZpdHRlZCxvYnM9eV90ZXN0KSMxLjU5NjQ0MgpgYGAKQ29tcGFyZSBsYXNzbyBhY3R1YWwgdmFsdWVzIGFuZCBwcmVkaWN0ZWQgdmFsdWVzCmBgYHtyfQp5X3Rlc3QuZGYgPC0gYXMuZGF0YS5mcmFtZShhcy52ZWN0b3IoeV90ZXN0KSkKeV90ZXN0LmRmCmBgYApgYGB7cn0KdGVzdF9wcmVkaWN0aW9uc19yZWZpdHRlZCA8LSBhcy5kYXRhLmZyYW1lKGFzLnZlY3Rvcih0ZXN0X3ByZWRpY3Rpb25zX3JlZml0dGVkKSkKdGVzdF9wcmVkaWN0aW9uc19yZWZpdHRlZAoKZmluYWxfcmVzdWx0czwtIGNiaW5kKHlfdGVzdC5kZix0ZXN0X3ByZWRpY3Rpb25zX3JlZml0dGVkLHhfdGVzdCkKIApmaW5hbF9yZXN1bHRzCgojc2VlIHRoZSByZXNpZHVhbHMgZm9yIGVhY2ggcGF5b3IgYW5kIHRyZWF0bWVudCBjb2Rlcy4KYGBgCgpgYGB7cn0KaGVhZCh4X3RyYWluVHJhbnNmb3JtZWQpCmBgYAoKYGBge3J9CnBsb3QobGFzc29fbW9kZWwpCmBgYAoKYGBge3J9CiByb3duYW1lcyhjb2VmKGZpdCxzPTAuMSkpCmBgYApgYGB7cn0KY29lZihmaXQscz0wLjEpCmBgYAoKYGBge3J9CnByaW50KGZpdCkKYGBgCmBgYHtyfQpwbG90KGxhc3NvX21vZGVsLHh2YXI9ImxhbWJkYSIsIGxhYmVsID0gVFJVRSkKYGBgCmBgYHtyfQpjdmZpdCA9IGN2LmdsbW5ldCh4X3RyYWluVHJhbnNmb3JtZWQseV90cmFpbikKYGBgCmBgYHtyfQpwbG90KGN2Zml0KQojaHR0cHM6Ly93ZWIuc3RhbmZvcmQuZWR1L35oYXN0aWUvZ2xtbmV0L2dsbW5ldF9hbHBoYS5odG1sCmBgYAoKYGBge3J9CmN2Zml0JGxhbWJkYS5taW4KYGBgCmBgYHtyfQpjb2VmKGN2Zml0LCBzID0gImxhbWJkYS5taW4iKQpgYGAKCgoKYGBge3J9CmxpYnJhcnkoY29lZnBsb3QpCmNvZWZwbG90KGxhc3NvX21vZGVsLHNvcnQ9J21hZ25pdHVkZScpCmBgYApgYGB7cn0KdHlwZW9mKHRyYWluU2V0KQpgYGAKYGBge3J9CnByZWRpY3RvcnMgPC0gY29sbmFtZXModHJhaW5TZXQpCmBgYAogCgoKIAoK